编程C++ 开发者

什么是 C++ 中的 'lvalue' 和 'rvalue'? 解释它们的区别,传递给函数的方式以及为什么会出现对 rvalue 的引用(rvalue references)?

用 Hintsage AI 助手通过面试

答案

在 C++ 中,lvalue(左值)是指向内存中有名称并可以引用的对象的表达式(例如变量)。rvalue(右值)是指没有名称、且在传统意义上不是对象的临时值(例如,结果 a + b,类型为 5 的字面量)。

lvalue 可以取地址,而 rvalue 不能(在引入 rvalue 引用之前)。用于将它们传递到函数中有:

  • 普通引用:void foo(const std::string& s); — 接收 lvalue 和 rvalue。
  • Lvalue 引用:void bar(std::string& s); — 仅接收 lvalue。
  • Rvalue 引用(C++11+):void baz(std::string&& s); — 仅接收 rvalue。

示例:

void takeValue(std::string& s) { } // lvalue void takeRValue(std::string&& s) { } // rvalue std::string s = "hello"; takeValue(s); // OK, lvalue takeRValue(std::string("hi")); // OK, rvalue

rvalue 引用用于高效传递临时对象,主要用于移动语义,以便移动资源而不是复制它们。

陷阱问题

表达式 std::move(obj) 会获得什么类型的引用(lvalue 还是 rvalue)?应用 std::move 后,对象会变成什么类别?

答案:

std::move(obj) 始终返回 rvalue 引用(T&&),但对象本身仍然是 lvalue,只是进行了显式转换。之后对这个对象的操作要非常小心(它可能处于不确定但有效的状态)。

示例:

std::string s = "data"; std::string d = std::move(s); // d 获取 s 的数据,s 现在为空

由于对主题细节的不熟悉而导致的实际错误示例。


故事

在一个大型项目中,一位开发者通过 lvalue 引用 T& 传递临时对象(而不是 T&&const T&)。这导致了编译错误和不优化的复制——移动语义未被使用,性能降低了 40%。


故事

在前端引擎中错误地将 std::move 应用于随后又使用的变量,导致变量处于 "破坏" 状态,引发了崩溃和渲染线程崩溃。


故事

在序列化库中将类型为 std::vector<T> 的容器作为 lvalue 传递给函数,而期待进行移动。结果是进行了大量元素的昂贵复制,严重降低了大数组的序列化时间。