C++中所有的值都可以分为左值
和右值
。
左值
左值是“有身份“的值。一个左值一定是能够被取地址的。
1 | int x = 5; // x 是左值 |
左值通常是程序中可持久化存在,能被频繁访问的对象。左值一定会被分配一个可操作的地址。
左值的生命周期通常较长,一般超出单个表达式的作用域。
右值
右值有两个核心特征: 可移动性 和 临时性。
C++11 之后,右值也可以分为两类。
- 纯右值
- 将亡值
纯右值
纯右值是纯粹的临时值,没有身份,不可以取地址。
通常,纯右值用来表示计算结果,非引用返回值,构造函数调用生成的临时对象。
1 | thread(func); // 这样的一个值是纯右值。 |
一个纯右值如果没有一个左值来接收,那么这个纯右值将会立即死去。
将亡值
将亡值是一个具有身份但即将被销毁的值。同样地,一个将亡值如果没有一个左值来接收,这个将亡值也会立即死去。
将亡值通常是被move
等标记过的值,或者右值引用返回值。
通过将亡值,C++支持了移动语义
。
利用移动语义,我们可以将资源从一个实例转移
到另一个实例。在某些情况下,这十分关键。
例如,智能指针unique_ptr
具有独占所有权的机制。所以在unique_ptr
间转移资源时,移动语义非常有用。
1 | // 将一个unique_ptr的资源转移到另一个unique_ptr |
其中move()
的作用是让左值ptr1变成一个将亡值。
左值引用、右值引用与移动语义
C++11后,编译器支持使用&&
来表示一个右值引用。
1 | int a = 10; // 左值 |
move
可以将一个左值转化为一个右值引用,以便触发移动构造函数,从而使用移动语义。
与拷贝构造函数
类似,移动构造函数
也是通过不同的参数重载的构造函数。
1 | String(String&& other) |
在移动构造函数中,应该将管理资源的原裸指针置空。对于STL中的容器或者std::unique_ptr,应该使用move进行资源的移动。
而对于其他内置数据类型,则不必过多关心。