你是否也遇到过这样的编译错误:“不能将右值绑定到左值引用”?或者在阅读 C++11 的移动语义时被 T&&
弄得一头雾水?
这背后,都是“左值”和“右值”在作祟。
要想解决这些问题,首先要能区分左值与右值。
因此,本文的目的很简单,就是要让你明白这俩的区别,跨出解决问题的第一步。
什么是左值(Lvalue)和右值(Rvalue)
左值(Lvalue)
- 可以取地址、有名字、可以多次使用的实体,
- 通俗地说:是“有家”的变量
示例:
int x = 10;
int* p = &x; // x 是左值,可以取地址
右值(Rvalue)
- 没有名字、不能取地址、临时产生的值
- 通俗地说:是“没家”的临时值
示例:
int y = 5 + 3; // 5 + 3 是右值,表达式结果是临时的
左值与右值的例子
接下来让我们通过更多的代码示例来进行直观的理解。
左值示例
#include <iostream>
int main() {
int a = 10; // a 是左值,有名称和内存地址
int& ref = a; // 左值引用绑定到左值 a
a = 20; // 左值可以出现在赋值左侧
std::cout << "a = " << a << ", address = " << &a << std::endl; // a 是左值,可以取地址
return 0;
}
右值示例
#include <iostream>
int getValue() {
return 42; // 返回值是右值,临时生成
}
int main() {
int b = 10 + 20; // 10 + 20 是右值,计算结果是临时值,无名称且无法取地址
int c = getValue(); // getValue() 返回的 42 是右值
// std::cout << &getValue() << std::endl; // 错误!右值无地址
return 0;
}
左值与右值的关键区别
特性 | 左值 | 右值 |
---|---|---|
身份 | 有名称(如变量名) | 无名称(临时值、字面量) |
内存地址 | 可通过 & 获取地址 | 无法取地址 |
生命周期 | 持久(直到作用域结束) | 临时(表达式结束后销毁) |
赋值左侧 | 可以(如 x = 5 ) | 不可(如 10 = 5 非法) |
引用绑定 | 可绑到左值引用 T& | 可绑到右值引用 T&& (C++11) |
结语
左值和右值是C++表达式分类的基础,理解它们有助于我们更好地设计代码、调试问题和优化程序。
通过“是否有名称”“能否取地址”和“是否临时”这三个标准,你可以轻松判断一个表达式是左值还是右值。
希望本文的示例和说明能让你对这两个概念有清晰的认识!
本文首发于微信公众号《Linux在秋名山》,欢迎大家关注~