return 本地对象时的 C++11 移动语义

C++11 move semantics when return a local object

我看到了一些类似的问题,但找不到对我的问题的明确解释。这是代码(可以在这里找到:http://melpon.org/wandbox/permlink/nBiik8pMkpKCD3Jv):

#include <iostream>

class A {
  public:
  explicit A(int a)         {std::cout << "Main constructor" << std::endl;}
  A(const A& a)             {std::cout << "Copy constructor" << std::endl;}
  A& operator =(const A& a) {std::cout << "Copy assignment" << std::endl; return *this;}
  A(A&& a)                  {std::cout << "Move constructor" << std::endl;}
  A& operator =(A&& a)      {std::cout << "Move assignemnt" << std::endl; return *this;}
};

A getA(bool b)        {std::cout << "In getA" << std::endl; A a(0); return b ? a : A(1);}
A getA_Move(bool b)   {std::cout << "In getA_Move" << std::endl; A a(0); return std::move(b ? a : A(1));}

int main(void) {
    std::cout << "\nA a0(getA(true))" << std::endl;
    A a0(getA(true));
    std::cout << "\nA a1(getA(false))" << std::endl;
    A a1(getA(false));    
    std::cout << "\nA a2(getA(true))" << std::endl;
    A a2(getA_Move(true));
    std::cout << "\nA a3(getA(false))" << std::endl;
    A a3(getA_Move(false));    
}

据我了解:函数的 return 是右值(因为与左值相反,它没有名称,因此不能重复使用)。 因此,当创建一个将函数的 return 值作为参数的对象时,如果该参数是可移动的,则应移动该参数。然而,这不是我能观察到的:

Start


A a0(getA(true))
Main constructor
In getA
Copy constructor  <- Why is not this a move ?

A a1(getA(false))
Main constructor
In getA
Main constructor

A a2(getA(true))
Main constructor
In getA_Move
Copy constructor <- I would have expected a move here as well
Move constructor

A a3(getA(false))
Main constructor
In getA_Move
Main constructor
Move constructor

0

Finish

谢谢@T.C。我修改了程序以使用正常的 if 然后程序按预期工作。结果可以在这里找到:http://melpon.org/wandbox/permlink/6h0ODi1SHdUj4HvX

这是由于 copy elision 编译器优化。 “复制省略是唯一允许的可以改变可观察到的副作用的优化形式

简而言之,这是因为 foo ? lvalue-of-X : rvalue-of-X 导致从所选操作数初始化类型为 X 的临时值 - 如果选择第二个则为副本,如果选择第三个则为移动。

然后,该临时文件被 returned - 首先移入 return 值,然后移入 main 中的变量。

"local variables are treated as rvalues in return" 规则仅在所述局部变量被直接 returned 时适用。

GCC 在这里的处理有一点问题——它省略了第三个操作数的移动,即使是 -fno-elide-constructors。使用 clang,您会在选择第三个操作数时看到 the triple move