原文:http://www.cprogramming.com/c++11/rvalue-references-and-move-semantics-in-c++11.html
先看看这个例子:
#include <iostream> using namespace std; vector<int> doubleValues (const vector<int>& v) { vector<int> new_values( v.size() ); for (auto itr = new_values.begin(), end_itr = new_values.end(); itr != end_itr; ++itr ) { new_values.push_back( 2 * *itr ); } return new_values; } int main() { vector<int> v; for ( int i = 0; i < 100; i++ ) { v.push_back( i ); } v = doubleValues( v ); }调用函数doubleValues时是有两次复制的,一次是在函数返回时,因为local变量要被回收,所以需要 copy构造一个临时对象来返回,当返回这个临时对象后,又需要一次 copy赋值操作来赋值给v。你可能会说,不返回对象就可以啊,可以返回一个引用或者一个指针,但是要这样做就得分配内存,但是C++的一个设计目标就是尽量少分配内存。上述更糟糕之处在于,返回的临时对象使用完之后是会被销毁掉的。
理论上来说,在内存中我们完全可以把临时对象的指针偷过来,而不去拷贝。还有就是我们为什么不能move呢?C++03说,我不知道哪个对象是临时的,哪个不是临时的,但是C++11却可以做到。
这就是右值引用和move语义要做的事情:move语义可以使你在使用临时对象时避免拷贝,并且可以安全的使用临时对象里的资源。
左值和右值
C++中,左值是指可以使用其地址的表达式,左值提供一种(半)永久的内存,比如:
int a;
a = 1; //a是一个左值
又如:
intx; int& getRef () { returnx; }
getRef() = 4;//getRef()这个表达式也是一个左值,因为其提供的返回值全局变量,是有固定地址的。
intx; intgetVal () { returnx; } getVal();
string getName () { return"Alex"; }
getName();
string nema = getName();
const
string& name = getName();
// ok
string& name = getName();
// NOT ok
C++11中,会让你可以绑定一个mutable右值引用,也就是说,一个值是否临时的,可以使用右值引用来检测,右值引用使用&&语法,可以是const也可以是非const的:
const
string&& name = getName();
// ok
string&& name = getName();
// also ok - praise be!
printReference (constString& str) { cout << str; } printReference (String&& str) { cout << str; }
string me( "alex");//mutable rvalue-references类型 printReference( me ); // calls the first printReference function, taking an lvalue reference
现在,右值引用版本的函数就像一个俱乐部的入口,只有临时变量才可以进入。
现在,既然有方法检测出是否临时变量了,有什么用处呢?
class ArrayWrapper { public: ArrayWrapper (int n) : _p_vals( new int[ n ] ) , _size( n ) {} // copy constructor ArrayWrapper (const ArrayWrapper& other) : _p_vals( new int[ other._size ] ) , _size( other._size ) { for ( int i = 0; i < _size; ++i ) { _p_vals[ i ] = other._p_vals[ i ]; } } ~ArrayWrapper () { delete [] _p_vals; } private: int *_p_vals; int _size; };来看move构造:
class ArrayWrapper { public: // default constructor produces a moderately sized array ArrayWrapper () : _p_vals( new int[ 64 ] ) , _size( 64 ) {} ArrayWrapper (int n) : _p_vals( new int[ n ] ) , _size( n ) {} // move constructor ArrayWrapper (ArrayWrapper&& other) : _p_vals( other._p_vals ) , _size( other._size ) { other._p_vals = NULL; } // copy constructor ArrayWrapper (const ArrayWrapper& other) : _p_vals( new int[ other._size ] ) , _size( other._size ) { for ( int i = 0; i < _size; ++i ) { _p_vals[ i ] = other._p_vals[ i ]; } } ~ArrayWrapper () { delete [] _p_vals; } private: int *_p_vals; int _size; };