左右值
在C++中,下面三种对象需要调用拷贝构造函数(有时也称“复制构造函数”):
1) 一个对象作为函数参数,以值传递的方式传入函数体;
2) 一个对象作为函数返回值,以值传递的方式从函数返回;
3) 一个对象用于给另外一个对象进行初始化(常称为复制初始化);
临时对象大多数会被编译器优化掉的(RVO),意思就是不会调用函数返回值的构造和析构,也就不存在销毁不销毁问题了,对函数内临时对象的初始化语句会直接作用在外部的接受对象身上
A fun(){ A a; return a}函数中返回的也不是临时对象而是局部对象,如果是return A();这样子就会返回一个临时对象,也许编译器会对临时对象优化,大多数编译器都会做这个优化的,
effective C++中的条款.例如A aa = func();这样子函数的返回值就不会有构造和析构成本了,而是直接在aa对象空间中进行初始化操作.
已经关闭了返回值优化,g++4.8编译,参数-std=c++11 -g -fno-elide-constructors -O0
输出:
为什么调用的不是copy而是move,我理解函数test中的a是一个左值,在没有使用std::move(a)的情况下应该调用的copy.
虽然你用-fno-elide-constructors 关闭了返回值优化,但编译器发现变量a是局部变量,离开test函数后就会死亡。所以编译器把a变量当作将亡值(eXpiring Value)。编译器会为将亡值调用移动构造函数的。如果变量a用static修饰,那么就可以看到其调用的是复制构造函数。
千万不要返回右值引用,最佳实践可以看c++ - C++11 rvalues and move semantics confusion (return statement)
局部对象作为函数返回值时(值返回时),被视为“右值”。
分析:
如果在c++98或者03中,没有RVO,NRVO, 也没有move构造函数和move赋值函数,
A b = test(); 这会有两次copy 构造, 一次是return a,一次是A b= test().
A b; b = test(); 这会有一次copy构造,发生在return a,另外一次是赋值运算符.