请考虑以下事项:
#include <iostream>
#define trace(name) std::cout << #name << " (" << this << "), i = " << i << std::endl
class C
{
C(C const&);
C& operator=(C const&);
public:
int i;
C() : i(42) { trace(CTOR); }
C(C&& other) : i(other.i) { trace(MOVE); other.i = 0; }
C& operator=(C&& other) { trace(ASGN); other.i = 0; return *this; }
~C() { trace(DTOR); }
};
C
func1(bool c)
{
C local;
if (c)
return local;
else
return C();
}
int
main()
{
C local(func1(true));
return 0;
}
MSC和g ++都允许return local
,并在执行此操作时使用移动构造函数(如输出所示)。虽然这对我来说很有意义,而且我认为可能应该是这样,但我找不到授权它的标准中的文本。据我所知,移动构造函数的参数必须是prvalue(它显然不是)或xvalue;它实际上是一个左值,它会使返回与函数体中的C other = local;
一样非法(它无法编译)。
答案 0 :(得分:6)
当在C ++ 11中添加到C ++的移动语义时,决定在哪里自动移动构造。
遵循的一般规则是,当复制省略合法时,应该发生隐式移动。
当您有一个要复制到另一个实例的匿名对象时,复制elision是合法的。编译器可以合法地删除副本,并将这两个对象视为一个,其生命周期等于两个对象生命周期的并集。
复制省略合法的另一个时间是从函数返回局部变量。这被称为NRVO(命名为返回值优化)。 C ++ 03中的这种优化允许您声明一个返回值,它直接在返回值所在的位置构造。当您return retval;
时,不会发生任何副本。
当你在函数的不同位置返回多个不同的对象时,基本上不可能没有内联。
但是,当添加移动语义时,这个地方是可能发生隐式移动的另一个地方。返回与return local_var;
相同类型的变量的函数中的local_var
可以省略,和失败,您可以隐式地从local_var
移动到返回值
答案 1 :(得分:4)
C ++ 11 12.8 / 32:当满足或将满足复制操作的省略标准时,除了源对象是函数参数这一事实,并且要复制的对象由< em> lvalue ,首先执行选择复制构造函数的重载决策,好像该对象是由 rvalue 指定的。
返回本地自动变量符合elision标准;将它视为 rvalue 就像选择移动构造函数一样。