面试题:什么是 C++ 的左值和右值?有什么区别?

在 C++ 中,左值(Lvalue)右值(Rvalue)是表达式的两种基本分类,它们的主要区别在于值类别(Value Category)生命周期。理解左值和右值是掌握 C++ 中移动语义、完美转发等高级特性的基础。


1. 左值(Lvalue)

定义

  • 左值是指具有明确内存地址的表达式,可以出现在赋值操作的左侧。
  • 左值通常是一个具名对象,其生命周期超过当前表达式。

特点

  • 可以取地址(使用 & 操作符)。
  • 可以出现在赋值操作的左侧。
  • 通常是持久的,生命周期较长。

示例

int x = 10; // x 是左值
int* p = &x; // 可以取地址
x = 20; // 可以出现在赋值左侧

2. 右值(Rvalue)

定义

  • 右值是指临时对象字面量,通常没有明确的内存地址。
  • 右值通常是一个临时值,其生命周期仅限于当前表达式。

特点

  • 不能取地址(使用 & 操作符)。
  • 不能出现在赋值操作的左侧。
  • 通常是临时的,生命周期较短。

示例

int x = 10; // 10 是右值(字面量)
int y = x + 5; // x + 5 是右值(临时值)

3. 左值和右值的区别

特性左值(Lvalue)右值(Rvalue)
内存地址有明确的内存地址没有明确的内存地址
赋值操作可以出现在赋值左侧不能出现在赋值左侧
生命周期生命周期较长生命周期较短(仅限于当前表达式)
示例变量、具名对象字面量、临时值

4. 右值引用(Rvalue Reference)

C++11 引入了右值引用(&&),用于绑定右值,支持移动语义和完美转发。

示例

int x = 10;
int&& rvalueRef = 20; // 右值引用绑定到右值
int&& rvalueRef2 = std::move(x); // 使用 std::move 将左值转换为右值

5. 左值和右值的扩展分类

C++11 进一步将值类别细分为以下五种:

  1. Lvalue:左值。
  2. Prvalue:纯右值(Pure Rvalue),如字面量、临时值。
  3. Xvalue:将亡值(Expiring Value),如通过 std::move 转换的对象。
  4. Glvalue:广义左值(Generalized Lvalue),包括 Lvalue 和 Xvalue。
  5. Rvalue:右值,包括 Prvalue 和 Xvalue。

6. 示例代码

左值和右值的区别

int x = 10; // x 是左值
int y = x; // x 是左值,可以赋值给 y
int z = 20; // 20 是右值

// int& lref = 20; // 错误:不能将右值绑定到左值引用
const int& clref = 20; // 正确:可以将右值绑定到常量左值引用
int&& rref = 20; // 正确:可以将右值绑定到右值引用

右值引用的使用

void process(int& x) {
    std::cout << "Lvalue: " << x << std::endl;
}

void process(int&& x) {
    std::cout << "Rvalue: " << x << std::endl;
}

int main() {
    int x = 10;
    process(x); // 调用 process(int&)
    process(20); // 调用 process(int&&)
    return 0;
}

7. 总结

特性左值(Lvalue)右值(Rvalue)
定义具有明确内存地址的表达式临时对象或字面量
赋值操作可以出现在赋值左侧不能出现在赋值左侧
生命周期较长较短
右值引用不能绑定可以绑定

理解左值和右值的区别是掌握 C++ 中移动语义、完美转发等高级特性的基础。

THE END
点赞15 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容