(C++) 快速辨别左值和右值的两个方法

除夕夜,抢红包的间隙跑过来答一发知乎的提问~~


问题:C++左值和右值区别

问题:关于C++左值和右值区别有没有什么简单明了的规则可以一眼辨别?


看了一下现有的答案,讲概念和理论的多,谈可操作性的少。我来说两个办法吧,不过都不是俺原创的。

来自 Scott Meyers 的方法

判断表达式是否是左值,有一个简单的办法,就是看看能否取它的地址,能取地址的就是左值。

A useful heuristic to determine whether an expression is an lvalue is to ask if you can take its address. If you can, it typically is. If you can’t, it’s usually an rvalue. A nice feature of this heuristic is that it helps you remember that the type of an expression is independent of whether the expression is an lvalue or an rvalue.
-- "Effective Modern C++", Introduction - Terminology and Conventions, Scott Meyers

来自 Joseph Mansfield 的方法

理解下面的几句话就可以了,顺带也清楚地表达了 std::movestd::forward 的区别和联系

  • 左值可看作是“对象”,右值可看作是“值” (Lvalues represent objects and rvalues represent values)
  • 左值到右值的转换可看做“读出对象的值” (Lvalue-to-rvalue conversion represents reading the value of an object)
  • std::move 允许把任何表达式以“值”的方式处理 (allows you to treat any expression as though it represents a value)
  • std::forward 允许在处理的同时,保留表达式为“对象”还是“值”的特性 (allows you to preserve whether an expression represented an object or a value)

那么这里的“对象” (object) 和 “值” (value) 是什么意思呢?任何一个有价值的 C++ 程序都是如此:a) 反复地操作各种类型的对象 b) 这些对象在运行时创建在明确的内存范围内 c) 这些对象内存储着值。 (Every useful C++ program revolves around the manipulation of objects, which are regions of memory created at runtime in which we store values.)

这一句话的解释实际上就指向了上面的第一条方法——只有特定的内存区域才可以被取地址。

举个栗子

先定义一个变量,

int foo;

此时,

  • 表达式 foo 是一个左值,可以取地址 (&foo) (方法一),foo 本身是一个拥有明确内存范围的对象 (方法二)
  • 表达式 foo + 5 是一个右值,无法取地址 (&(foo + 5)) (方法一),是一个需要被存储到对象里的值 (方法二)

关于第二种方法,更详细的讨论可见下面 Joseph Mansfield 的文章。此文行文流畅,对理解 lvalue/rvalue/move/forward 很有帮助。


答完了,回去接着看春晚抢红包。

[完]
Gu Lu
[2016-02-07]

知识共享许可协议
本作品由Gu Lu创作,采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可。