文档目录

在现代 C++ 中,一个表达式有两个独立维度的属性:

  1. 拥有身份(Has Identity):在内存中有固定的、可寻址的物理地址。
  2. 可被移动(Can be Moved):生命周期即将结束,它的资源(比如堆内存)允许被别人无损接管。

根据这两个维度的组合,C++ 官方将所有的“值(Value)”严格划分为了三大主类:

                     ┌──────────────────┐
                     │   表达式(Value) │
                     └────────┬─────────┘
                              ▼
            ┌─────────────────┴─────────────────┐
            ▼                                   ▼
   【有身份 / 内存可寻址】                    【临时数据 / 可被移动】
      (Has Identity)                       (Can be Moved)
            │                                   │
      ┌─────┴───────────┐                 ┌─────┴───────────┐
      ▼                 ▼                 ▼                 ▼
   左值 (lvalue)    将亡值 (xvalue)   将亡值 (xvalue)   纯右值 (prvalue)

1. 左值 (lvalue) —— 有身份,不可移动

  • 本质:指代一个持久存在的内存对象。只要你能用 &(取地址符)拿到它在内存中的物理地址,它就是左值。
  • 特点:有名字,生命周期由作用域决定,编译器不能随意销毁它。
  • 常见示例:变量名 a、函数名、左值引用 int& r = a;、解引用表达式 *ptr。

2. 纯右值 (prvalue) —— 无身份,可移动

  • 本质:纯粹的临时字面量或运算产生的临时过渡数据。它们在物理内存中没有独立的持久身份(你没办法对它们取地址)。
  • 特点:没有名字,生命周期极短,通常只存在于 CPU 寄存器或编译器的临时栈帧中。
  • 常见示例:字面量 42、'a';算术表达式 a + b;函数返回的临时非引用对象(如 std::string("hello"))。

3. 将亡值 (xvalue) —— 有身份,可移动(现代 C++ 零拷贝的精髓 ✨)

  • 本质:这是一个虽然在内存中有地址,但它马上就要被销毁(即将死亡)的对象。
  • 特点:因为它有身份,所以你可以找到它;因为它可移动,这意味着你被允许去“合法压榨”它,把它的堆内存指针据为己有。
  • 常见示例:最典型的将亡值就是通过 std::move(a) 强转出来的结果,或者返回右值引用的函数调用。