我一直在使用右值引用和移动语义进行测试,并希望确保我了解何时应省略拷贝以及何时应遵循移动语义。

鉴于以下

class NRVCA
{
public:
    NRVCA(int x):
    {}
    NRVCA(const NRVCA & Rhs)
    {}
    NRVCA& operator=(const NRVCA& dref)
    {}
};

NVCRA GetATemp()
{
   return NVCRA(5);
}

NVCRA GetACopy()
{
   NVCRA ret(5);
   ...
   return ret;
}

int main()
{
    //This call will be elided allays and invoke the single param constructor
    NVCRA A = GetATemp();
    //This call will be a traditional copy the complier may elide this
    // if so the work will be done inline
    NVCRA B = GetACopy();

}

在这种情况下,移动语义没有任何作用,与 C++11 中的 C++03 的唯一区别是,编译器不需要省略,而是需要省略。

所以
问题 1. 在什么情况下我可以保证复制构造函数会或不会被省略。

问题 2. 有没有办法强制编译器不省略。

问题 3. 假设您有逻辑一致的复制操作,我不希望编译器这样做是否有任何合乎逻辑的原因。

问题 4. 如果我定义了一个移动构造函数,无论如何都不会删除拷贝的情况下会发生移动。这是否会影响我的类(class)设计。

最佳答案

  • 消除复制和移动始终是可选的优化,标准不保证何时完成。 Elision 与选择移动复制的编译器不同。该语言保证何时根据其正常的重载解析规则选择移动构造或移动分配。
  • 一些编译器提供了一个标志来关闭省略。 gcc 和 clang 有 -fno-elide-constructors 。 MSVC 没有具体选项,但是禁用优化可能会避免一些省略(但有些无论如何都无法关闭,例如 Foo x = 1; 中的拷贝)
  • 我不知道有什么理由不在生产版本中省略拷贝/移动。
  • 有些人建议在返回“重”类时不要依赖“返回值优化”,因为无法保证 RVO。就我个人而言,我只是确认我的编译器很擅长它并继续进行。现在可以移动对象,您不再需要担心编译器是否支持此类优化,因为即使不支持,您仍然会得到移动而不是拷贝。
  • 10-08 11:51