C++ 右值引用
C++ 右值引用
C++11中一个最主要的特性是可以移动而非拷贝对象的能力。我们很多情况下都会发生对象拷贝,而在其中某些情况下,对象拷贝之后就立即背销毁了。这种情况下,移动而非拷贝对象会大幅度提升性能。
在C++11之前,没有直接的方法移动对象。因此,计时不必拷贝对象的情况下,我们也不得不拷贝。如果对象较大,或者是对象本身要求分配内存空间(如string),进行不必要的拷贝代价非常高。
为了支持移动操作,C++11中引入了一种新的引用类型————右值引用(rvalue
reference)。所谓右值引用是就是必须绑定到右值的引用。我们通过&&
而不是&
来获得右值引用。比如我们将要看到的,右值引用有一个重要的性质————只能绑定到一个将要销毁的对象上。因此,我们可以自由地将一个右值引用的资源“移动”到另一个对象中。
如我们所知,对于常规引用(为了与右值引用区分开,我们可以称之为左值引用),我们不能将其绑定到要求转换的表达式、字面常量、或者是返回右值的表达式。右值引用有完全相反的特性:我们可以将一个右值绑定到一个左值上,但不能将一个右值引用直接绑定到一个左值上。
1 |
|
返回左值引用的函数,连同赋值、下标、解引用和前置递增/递减运算符,都是返回左值的表达式的例子。我们可以将一个左值引用绑定到这类表达式的结果上。
返回非引用类型的函数,连同算数、关系、位以及后置递增/递减运算符,都生成右值。我们不能将一个右值引用绑定到这类表达式上,但我们可以将一个const的左值引用或一个右值引用绑定到这类表达式上。
左值持久;右值短暂
考察左值和右值表达式的列表,两者相互区别之处就很明显了:左值有持久的状态,而右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。
由于右值引用只能绑定到临时对象,我们得知
- 所引用的对象将要别销毁
- 该对象没有其他用户
这两个特性意味着:使用右值引用的diamagnetic可以自由地接管所引用对象的资源.
变量是左值
变量可以看作只有一个变量没有运算符的表达式,虽然我们很少这样看待变量.类似其他任何表达式,变量表达式也有左值/右值属性.变量表达式都是左值,带来的结果就是,我们不能将一个右值引用绑定一个右值引用类型的变量上
1 |
|
其实有了右值表示临时对象这一观察结果,变量是左值这一特性并不令人惊讶.毕竟,变量是持久的,直至离开作用域的时候才被销毁.
std::move函数
虽然不能将一个右值引用直接绑定到一个左值上,但是我们可以显式地将一个左值转换为对应的右值引用.我们还可以通过调用一个名为move
的函数来获得绑定到左值上的右值引用.move
函数可以返回给定对象的右值引用.
1 |
|
move
调用告诉编译器:我们有一个左值,但我们希望像一个右值一样处理它.调用move
就意味着承诺:除了对rr1
赋值或销毁它外,我们将不再使用它.在调用move
之后,我们不能对移后源对象的值做任何假设.(我们可以销毁一个移后源对象,也可以赋予它新值,但不能使用一个移后源对象的值)