左值右值
1. 概念
概念 |
简明解释 |
左值(lvalue) |
有名字、有地址的对象,能出现在赋值号左边 |
右值(rvalue) |
没有名字、临时存在的值,只能出现在赋值号右边 |
举例:
int a = 10;
int b = a + 5;
表达式 |
类型 |
说明 |
a |
左值 |
有名字,可以 &a 取地址 |
10 |
右值 |
临时值,不能取地址 |
a + 5 |
右值 |
表达式结果是临时值 |
b |
左值 |
是变量 |
2. 如何判断
能否被赋值? |
能否取地址? |
类型 |
✅ |
✅ |
左值 |
❌ |
❌(大部分情况) |
右值 |
int x = 42;
&x; // ✅ 左值能取地址
&(x + 1); // ❌ 编译错误,右值不能取地址
3. 常见的左值右值
示例 |
类型 |
说明 |
变量 x |
左值 |
有地址、可以赋值 |
字面量 10 |
右值 |
没地址、不能取地址 |
x + 1 |
右值 |
运算结果是一个临时值 |
"abc" |
右值 |
字符串字面量是临时值 |
函数返回值(返回非引用) |
右值 |
|
函数返回引用 |
左值 |
|
4. 与引用的关系
引用类型 |
能绑定右值 |
能绑定左值 |
用途 |
T& |
❌ |
✅ |
修改已有变量 |
const T& |
✅ |
✅ |
安全地读取,不可修改 |
T&& |
✅ |
❌ |
专门操作右值,进行移动 |
int a = 10;
int& r1 = a; // ✅ 左值引用绑定左值
int& r2 = 10; // ❌ 错误,不能绑定右值
const int& r3 = 10; // ✅ 常量引用可以绑定右值
int&& r4 = 10; // ✅ 右值引用绑定右值
5. 右值引用
语法是 T&&
,只允许绑定右值(不能绑定有名字的变量)。右值引用让你可以“接住”临时对象的资源,然后偷走它们,而不是复制。
移动语义
std::string a = "hello";
std::string b = std::move(a); // move 后,a 的资源转移给 b
std::string s1 = "abc";
std::string s2 = s1; // 拷贝构造(复制内容)
std::string s3 = std::move(s1); // 移动构造(直接窃取 s1 的资源)
移动构造函数/赋值运算符
class MyClass {
public:
MyClass(MyClass&& other) {
// 把 other 的资源“偷”过来
}
MyClass& operator=(MyClass&& other) {
// 先释放自己资源,再接管 other's
return *this;
}
};