通过常量左值引用,可以延长ReturnValue()返回值的生命周期,但是不能修改它。C++11的右值引用出场了:
std::move乍一看没什么用。它主要用在两个地方:
A&& a3 = ReturnValue();
右值引用通过”&&”来声明, a3引用了ReturnValue()的返回值,延长了它的生命周期,并且可以对该临时值进行修改。
二. 移动语义
右值引用可以引用并修改右值,但是通常情况下,修改一个临时值是没有意义的。然而在对临时值进行拷贝时,我们可以通过右值引用来将临时值内部的资源移为己用,从而避免了资源的拷贝:
#include<iostream>
class A
{
public:
A(int a)
:_p(new int(a))
{
}
// 移动构造函数 移动语义
A(A&& rhs)
: _p(rhs._p)
{
// 将临时值资源置空 避免多次释放 现在资源的归属权已经转移
rhs._p = nullptr;
std::cout<<"Move Constructor"<<std::endl;
}
// 拷贝构造函数 复制语义
A(const A& rhs)
: _p(new int(*rhs._p))
{
std::cout<<"Copy Constructor"<<std::endl;
}
private:
int* _p;
};
A ReturnValue() { return A(5); }
int main()
{
A a = ReturnValue();
return 0;
}
运行该代码,发现Move Constructor被调用(在g++中会对返回值进行优化,不会有任何输出。可以通过-fno-elide-constructors关闭这个选项)。在用右值构造对象时,编译器会调用A(A&& rhs)形式的移动构造函数,在移动构造函数中,你可以实现自己的移动语义,这里将临时对象中_p指向内存直接移为己用,避免了资源拷贝。当资源非常大或构造非常耗时时,效率提升将非常明显。如果A没有定义移动构造函数,那么像在C++98中那样,将调用拷贝构造函数,执行拷贝语义。移动不成,还可以拷贝。
std::move:
C++11提供一个函数std::move()来将一个左值强制转化为右值:
A a1(5);
A a2 = std::move(a1);
上面的代码在构造a2时将会调用移动构造函数,并且a1的_p会被置空,因为资源已经被移动了。而a1的生命周期和作用域并没有变,仍然要等到main函数结束后再析构,因此之后对a1的_p的访问将导致运行错误。std::move乍一看没什么用。它主要用在两个地方:
- 帮助更好地实现移动语义
-
实现完美转发(下面会提到)
考虑如下代码:
class B { public: B(B&& rhs) : _pb(rhs._pb) { // how can i move rhs._a to this->_a ? rhs._pb = nullptr; } private: A _a; int * pb; }










