左值是有名字、能取地址、生命周期长的表达式,如变量a、arr[2];右值是无名、不可取地址、临时的值,如字面量42、a+b;std::move仅作类型转换,将左值转为右值引用以支持移动语义等核心机制。

左值和右值不是看它在等号左边还是右边,而是看它有没有“身份”——能不能被取地址、有没有名字、生命周期是否足够长。
左值:有名字、能取地址、活得久
左值是程序中真实存在的、可定位的对象。它有变量名,内存地址固定,表达式结束后还能继续用。
- 变量本身(int a = 5; 中的 a)
- 数组元素(arr[2])、解引用指针(*p)
- 返回左值引用的函数调用(如 vec[0]、++i)
- 可以用 &a 取地址,也能反复读写
右值:没名字、不能取地址、一闪而过
右值是临时产生的、无名的值,只在当前表达式中有效,表达式一结束就销毁。
- 字面量(42、"hello")
- 表达式结果(a + b、i++)
- 函数返回非引用类型(int func() { return 10; } 的返回值)
- &(a + b) 编译报错,因为它没有内存地址可取
关键细节:别被表象骗了
同一个东西,在不同上下文里可能是左值或右值。比如变量 x 是左值,但写成 std::move(x) 就变成右值;func() 返回右值,但如果它返回的是 int&,那结果就是左值。
立即学习“C++免费学习笔记(深入)”;
- 左值引用(int& r = x;)只能绑定左值
- 右值引用(int&& r = 42;)只能绑定右值(含将亡值)
- 右值引用变量自己是左值(因为它有名字、能取地址)
- std::move 不移动任何东西,只是类型转换——把左值“标记”为可移动的右值
为什么这个区分重要
它直接支撑现代 C++ 的核心机制:
- 移动语义:对右值资源“偷过来”,避免深拷贝
- 完美转发:模板函数保留实参的左/右值属性
- 编译器优化:知道哪些值可以复用、哪些必须保护
- 错误拦截:禁止给字面量赋值(5 = 10; 直接报错)










