学习定位:现代 C++ 核心知识。右值引用是理解移动语义和 std::move 的前置概念;普通开发者先掌握基础值类别和“可被移动”的含义即可。
右值引用是 C++11 引入的一种新的引用类型,用
T&&表示。它是实现移动语义和完美转发的基础。
1. 左值与右值
在理解右值引用前,必须分清左值和右值。
| 类别 | 定义 | 示例 |
|---|---|---|
| 左值(lvalue) | 有内存地址的表达式,可以取地址,通常出现在赋值左侧 | 变量名、*ptr、数组元素、函数返回左值引用的调用 |
| 右值(rvalue) | 临时对象、字面量、即将被销毁的值,不能取地址 | 42、a+b、std::move(x)、函数返回非引用类型 |
int x = 42; // x 是左值,42 是右值
int& ref = x; // 左值引用,只能绑定左值
// int& ref2 = 42; // 错误,左值引用不能绑定右值
const int& cref = 42; // const 左值引用可以绑定右值(延长生命周期)2. 右值引用语法
- 右值引用用
&&声明,只能绑定右值。 - 作用:标识一个对象是临时的、可被“窃取”资源的。
int&& rref = 42; // 右值引用绑定到字面量(右值)
int x = 10;
// int&& rref2 = x; // 错误,不能绑定左值
int&& rref3 = std::move(x); // std::move 将左值转为右值引用3. 右值引用的特性
- 延长临时对象生命周期(类似
const &,但可修改) - 区分移动语义:重载函数时,右值引用参数匹配临时对象
- 用于移动构造函数/赋值:见移动语义笔记
void process(const int& x) { std::cout << "copy\n"; }
void process(int&& x) { std::cout << "move\n"; }
int main() {
int a = 5;
process(a); // 输出 copy(左值)
process(10); // 输出 move(右值)
process(std::move(a)); // 输出 move
}4. 右值引用与左值引用的区别
| 类型 | 语法 | 绑定对象 | 可修改 | 能否延长临时对象生命周期 |
|---|---|---|---|---|
| 左值引用 | T& | 只能左值 | 是 | 否 |
| const 左值引用 | const T& | 左值或右值 | 否 | 是(但只读) |
| 右值引用 | T&& | 只能右值 | 是 | 是(可修改) |
5. 常见误区
- 右值引用本身是左值:一旦右值引用变量有了名字,它在后续代码中就是一个左值。
int&& rref = 42;
int* p = &rref; // 合法,rref 有地址,是左值
int&& rref2 = rref; // 错误,rref 是左值,不能绑定到右值引用这一特性解释了为什么移动构造函数中需要
std::move来再次转为右值引用。
下一节 移动语义