C++ 的左值(lvalue)和右值(rvalue)是 C++ 语言中一个非常基础但又极其重要的概念。它们是 C++ 表达式(expression)的两种基本属性,深刻地影响着代码的性能和写法,尤其是在 C++11 标准引入“移动语义”(Move Semantics)之后。

简单来说,区分左值和右值的核心标准是:这个表达式所代表的数据,我们还能不能在后面的代码里再次访问到它。

  • 左值 (lvalue - locator value):指那些在内存中有固定地址可以被取地址(用 & 运算符)并且在表达式结束后依然存在的表达式。你可以把它想象成一个有名字、有固定地址的“容器”。

  • 右值 (rvalue - read value):指那些临时的没有固定地址、在表达式结束后就会被销毁的表达式。你只能读取它的值,但不能对它取地址(通常情况下)。可以把它看作一个“即用即弃”的临时数据。


一、从“赋值操作符”的左右看起(经典 C++98 时代)

在 C++ 的早期,最简单的区分方法是看它能否出现在赋值操作符 = 的左边:

  • 能放在 = 左边的,就是左值。 因为放在左边意味着你要给它赋值,它必须有一个明确的、持久的存储位置。

  • 不能放在 = 左边的,就是右值。 因为它们是临时的,给一个即将销毁的东西赋值是毫无意义的。

示例:

1
2
3
4
5
6
7
8
9
int a = 10; // 'a' 是左值,因为它有内存地址,我们可以反复使用它。'10' 是右值,它是一个字面量,没有固定地址。

int b = 20; // 'b' 是左值。

a = b; // 正确:'a' 和 'b' 都是左值。

// 下面的都是错误的,因为等号左边不是一个合法的左值
// 10 = a; // 错误!10 是一个右值(字面量)。
// (a + b) = 30; // 错误!(a + b) 的计算结果是一个临时值,是右值。

常见的左值:

  • 变量名 (a, b)

  • 数组元素 (arr[0])

  • 返回左值引用的函数调用 (get_a_reference())

  • 解引用的指针 (*p)

常见的右值:

  • 字面量 (10, true, 'c')

  • 算术表达式的结果 (a + b)

  • 返回非引用类型的函数返回值 (get_a_value())

  • Lambda 表达式


二、C++11 的革命:右值引用的诞生与移动语义

到了 C++11 标准,情况变得更加有趣和重要。为了解决临时对象产生的深拷贝(deep copy)带来的巨大性能开销,C++11 引入了右值引用(Rvalue Reference)和移动语义(Move Semantics)


三、现代 C++ 的值类别(C++11 及以后)

为了更精确地描述表达式的属性,C++11 以后将值的类别划分得更细,分为五个类别:

  1. 左值 (lvalue): 传统的左值,有固定身份和位置。

  2. 纯右值 (prvalue - pure rvalue): 传统的右值,比如字面量 10true,以及函数返回的非引用临时对象。它们是“纯粹”的值,不与任何具体对象相关联。

  3. 将亡值 (xvalue - expiring value): 这是 C++11 新增的概念。它代表那些生命周期即将结束的对象,通常是 std::move 的结果或返回右值引用的函数调用。它虽然像右值一样资源可以被窃取,但它又和某个具体的对象(曾经是左值)相关联。

这五个类别之间有如下关系:

  • 广义左值 (glvalue - generalized lvalue) = 左值 + 将亡值。(表示有身份的对象)

  • 右值 (rvalue) = 纯右值 + 将亡值。(表示可以被移动的对象)

对大多数开发者而言,你不需要每天都去记忆这五个类别的精确定义。你只需要理解核心思想:

  • 左值:有名字、能取地址、持久的对象。

  • 右值:临时的、即将销毁的、可以被“移动”的对象。

  • std::move:一个“授权”,允许编译器将一个左值当作右值来处理,以便触发移动语义。

总结

特性 左值 (lvalue) 右值 (rvalue)
核心含义 持久的对象,有固定内存地址 临时的值,表达式结束后即销毁
能否取地址 (&) 可以 通常不可以(将亡值是例外)
能否在 = 左边 可以 不可以
绑定到引用类型 左值引用 (T&) 右值引用 (T&&)
与性能的关系 通常涉及拷贝(Copy) 允许移动(Move),性能更高
典型例子 变量名、数组元素 字面量、表达式结果、std::move的结果

理解左值和右值的区别是掌握现代 C++ 内存管理和性能优化的关键。它不仅是理论知识,更是编写高效、优雅代码的基石。