可以记:
C 里面有左值概念,但“右值体系”是 C++ 为了对象生命周期和移动语义扩展出来的。
简单说:C 语言里面有“左值(lvalue)”这个概念,但没有 C++ 那么完整的“左值/右值体系”。
C++ 的左值、右值概念是从 C 继承来的,但后来扩展得非常复杂,尤其是为了支持移动语义(move semantics)和右值引用(&&)。
1. C 语言里的左值(lvalue)
C 语言标准里有 lvalue。
简单理解:
左值:表示一个有存储位置(地址)的对象,可以出现在赋值号左边。
例如:
inta=10;a=20;这里:
a是左值20是常量,不是左值
因为:
&a可以取得地址:
printf("%p",&a);说明a有内存位置。
再比如:
intarr[10];arr[3]=100;arr[3]是左值。
因为它代表数组中的一个真实内存位置。
2. C 里面有没有右值(rvalue)?
严格来说:
C 标准没有正式定义 rvalue 这个术语。
但是 C 程序员通常会这样理解:
不能作为左值使用的表达式,就是“右值”。
例如:
inta;a=1+2;这里:
1+2产生一个临时结果,没有独立存储位置。
所以通常称为:
右值例如:
intx;x=x+1;右边:
x + 1是一个计算结果。
它没有地址:
&(x+1)// 错误所以不是左值。
3. C 和 C++ 最大区别
C:
大概只有:
左值 | +-- 非左值(通常叫右值)例如:
inta;a=5;a 左值 5 非左值 a+5 非左值C++:
后来发展成:
表达式类别 expression | -------------------- | | glvalue rvalue | | -------- ---------- | | | | lvalue xvalue prvalue也就是:
左值 纯右值 将亡值4. 为什么 C++ 要搞这么复杂?
主要为了:
std::move()和移动构造。
例如:
std::string a="hello";std::string b=a;复制:
a | 复制数据 | b比较慢。
C++11:
std::string b=std::move(a);告诉编译器:
a 不需要保留了,可以把内部资源直接搬走。
这需要区分:
- 还有用的对象(lvalue)
- 可以被移动的临时对象(xvalue)
5. 一个 C/C++ 对比例子
C:
inta=10;int*p=&a;可以:
a | 地址所以:
a 是左值C++:
inta=10;int&&b=20;这里:
20是纯右值(prvalue)
但是:
std::move(a)得到:
xvalue(将亡值)它有地址,但是允许被移动。
6. 一个容易混淆的地方
很多人认为:
左值就是变量,右值就是常量
这个在 C 里大致有用,但不完全正确。
例如:
inta;(a)=10;(a)仍然是左值。
再比如:
intarr[5];arr[0]不是变量名,但也是左值。
因为它代表一个对象。
总结:
| C | C++ | |
|---|---|---|
| 左值 | 有 | 有 |
| 右值 | 没有正式分类 | 有严格定义 |
| xvalue | 没有 | 有 |
| &&右值引用 | 没有 | 有 |
| 移动语义 | 没有 | 有 |
所以可以记:
C 里面有左值概念,但“右值体系”是 C++ 为了对象生命周期和移动语义扩展出来的。