0

根据我的理解,下面的代码应该调用Test类的移动构造函数,因为这个函数是按值返回的,这意味着表达式GetTestObj()应该是右值并且xvalues被隐式移动但是为什么这段代码调用复制构造函数?

class Test
{
  public:
         Test()
         {
         }
         Test(const Test& arg)
         {
            std::cout<<"Copy Constructor Called..."<<std::endl;
         }
         Test(Test&& arg)
         {
            std::cout<<"Move Constructor Called..."<<std::endl;
         }
};

Test  GetMyTestObj()
{
      Test *ptr = new Test();
      return *ptr;
}
Test dummy = GetMyTestObj(); //Copy Constructor Called...
4

3 回答 3

2

在您的代码中,实际上有一份 from*ptr到返回值,一份从GetMyTestObj()to移动dummy。但是,编译器忽略了这个动作,所以你不会看到它被跟踪。如果您传递-fno-elide-constructors给 GCC 或 Clang,那么您应该会看到副本和移动(演示)。

如果要将返回值构造为移动,则需要使用std::move

Test GetMyTestObj()
{
      Test *ptr = new Test();
      return std::move(*ptr);
}

但是,在这种情况下确实不需要动态分配。它效率低下,并且您的实现会泄漏内存。你应该只使用一个自动变量:

Test GetMyTestObj()
{
    Test test;
    //I assume you're doing something else here
    return test;
}

使用上面的代码,编译器实际上可以省略这两种结构。

如果你在那个函数中什么都不做,你应该直接构造dummy

Test dummy{};
于 2016-11-07T08:37:01.903 回答
0

值不是在这里复制的(由于复制省略,没有调用构造函数):

Test dummy = GetMyTestObj();

但在这儿:

return *ptr;

因为函数必须从左值引用生成右值对象。基本上,GetMyTestObj()这种情况下的函数相当于:

Test *ptr = new Test();
Test returnValue(*ptr);
return returnValue;
于 2016-11-07T08:38:46.357 回答
0

这意味着表达式GetTestObj()应该是右值并且 xvalues 被隐式移动

首先,直接回答你的问题,GetTestObj()prvalue

  • 非引用返回类型的函数调用或重载运算符表达式,例如str.substr(1, 2),str1 + str2it++;

关键是需要复制/移动操作return *ptr;ptr是一个命名变量,它是一个左值*ptr也是左值,不能移动。

您可以std::move显式使用使其成为可移动的 xvalue:

return std::move(*ptr);
于 2016-11-07T08:34:16.140 回答