✅ AI优化后的笔记
📌 一、左值(Lvalue)和右值(Rvalue)
✳️ 左值(Lvalue)
表示持久存在的对象,有确定的内存地址
可以出现在赋值号(
=
)左边(虽然这不是定义本身,只是它的一个特性)可以用
&
取地址变量、数组元素、返回左值的函数等
int a = 5; // a 是左值
int* p = &a; // 可以取地址
✳️ 右值(Rvalue)
通常是临时对象,没有名字,也没有明确的内存地址
不能取地址(非 const 引用不能绑定)
不能出现在赋值号左边
字面量、表达式结果、返回右值的函数等
int b = 3 + 2; // 3 + 2 是右值
int x = 10; // 10 是右值
📌 二、右值的分类
✅ 补充解释:
纯右值(prvalue):表示纯粹计算结果,如字面量、算式。
3 + 4
、"hello"
、SomeClass()
是纯右值。亡值(xvalue, eXpiring value):将要被“搬走”的资源对象,生命周期即将结束,比如
std::move(obj)
、返回右值引用的函数。
📌 三、引用种类及绑定规则
🟢 左值引用(T&
)
只能绑定到左值
会延长左值的生命周期
可用于修改原值
int a = 10;
int& ref = a; // ok
ref = 20; // a 被修改
🔴 右值引用(T&&
)
只能绑定到右值(包括亡值)
不会延长右值生命周期
主要用于移动语义(move semantics)
int&& r = 10; // ok: 绑定右值
int&& r2 = std::move(a); // ok: 将 a 转成右值
📌 四、std::move 的真相
✅ 功能
不是“移动”,只是将左值强制转为右值
触发移动构造 / 移动赋值
用于资源转移(节省拷贝成本)
🔎 实现原理(简化)
template<typename T>
constexpr std::remove_reference_t<T>&& move(T&& t) noexcept {
return static_cast<std::remove_reference_t<T>&&>(t);
}
❗ 注意
std::move
不会改变对象状态被 move 的对象应视为“有效但未指定状态”,不要再用它除非重赋值
📌 五、引用折叠(高级补充)
如果你深入泛型编程,会遇到这个概念:
template<typename T>
void func(T&& arg); // 万能引用 / 转发引用
// 若传入左值 => T = int&,T&& = int& && => int&
// 若传入右值 => T = int,T&& = int&&
这就是 引用折叠规则(reference collapsing),现代 C++ 的重要技巧。
✅ 总结:一张图理解
表达式值分类:
┌──────────────┐
│ 表达式 │
└──────┬───────┘
│
┌─────▼───────┐
│ 左值 │ 可取地址,可修改,绑定左值引用
└─────┬───────┘
│
┌─────▼──────────┐
│ 右值 │
└─────┬──────┬───┘
│ │
┌───▼──┐ ┌──▼────┐
│纯右值│ │ 亡值 │
└──────┘ └───────┘
评论