Chr*_*utz 27

左值是可以被分配给一个值:

lvalue = rvalue;
Run Code Online (Sandbox Code Playgroud)

这是短期的"左值"或"左侧值",它基本上只是数值上的左边的的=迹象,即价值分配的东西.

作为不是左值的例子(即仅rvalue):

printf("Hello, world!\n") = 100; // WTF?
Run Code Online (Sandbox Code Playgroud)

该代码不起作用,因为printf()(返回一个函数int)不能是左值,只能是右值.

  • +1好看!"// WTF"让我开怀大笑!但是,如果printf返回引用,它将有资格作为左值. (3认同)

小智 12

出现在赋值左侧的东西,即可以分配给它的东西.

请注意,在C++中,函数调用可能是左值,如果:

int & func() {
   static int a = 0;
   return a;
}
Run Code Online (Sandbox Code Playgroud)

然后:

func() = 42;     // is legal (and not uncommon)
Run Code Online (Sandbox Code Playgroud)

  • 不是那么奇怪 - 它是operator []正常工作的方式 (2认同)

Joh*_*itb 12

它传统上是"="运算符的左侧.但是,随着时间的推移,"左值"/"右值"的含义发生了变化.C++添加了一个"不可修改的左值"的术语,它是任何无法赋值的左值:数组和用"const"限定的变量是两个例子.在C中,您不能分配任何右值(见下文).同样,在C++中,您不能分配给某些用户定义的类类型的rvalues.

您可以说"左值"是一个表达式,用于命名随时间持续存在并占据存储位置的对象.是否可以分配该表达式对于该分类并不重要.特别是,引用也是左值,因为它的名称会随着时间的推移而持续存在.以下所有都是左值,因为它们都引用了命名对象.另请注意,a const对左值没有任何影响.

int a; lvalue: a;
       lvalue: ++a;
int a[2]; lvalue: a;
int &ra = a; lvalue: ra;
int *pa = &a; lvalue: *pa;
Run Code Online (Sandbox Code Playgroud)

术语"rvalue"用于文字和枚举器值以及不享受长寿的乐趣的临时演员,并且在完整表达结束时立即被销毁.对于右值,不是持久性方面很重要,而是价值方面.C++中的函数是左值,因为它们是持久的并且它们具有地址,即使它们不是对象.我在上面的左值概述中将它们排除在外,因为当首先考虑对象时,更容易掌握左值.以下所有是rvalues:

enum { FOO, BAR }; rvalue: BAR;
int a[2]; rvalue: (a+1);
rvalue: 42;
int a; rvalue: a++; // refering to a temporary
struct mystruct { }; mystruct f() { return mystruct(); } rvalue: f();
Run Code Online (Sandbox Code Playgroud)

顺便提一下,通常你有一个左值,但是运算符需要一个右值.例如,二进制内置"+"运算符添加两个值.首先和全部的左值表达式指定首先必须读出值的位置.因此,当您添加两个变量时,会发生"左值到右值"转换.标准表示左值表达式中包含的值是其右值结果:

int a = 0, b = 1;
int c = a + b; // read values out of the lvalues of a and b. 
Run Code Online (Sandbox Code Playgroud)

其他运营商不采用右值,而是左值.他们没有阅读价值.一个例子是address-of运算符,&.您不能获取右值表达式的地址.有些rvalues甚至不是对象:它们不占用任何存储空间.例如,文字(10,3.3,...)和枚举值.

那些可怕的东西有用吗?

好吧,它具有区分左值和右值的几个优点

  • 允许编译器省略为rvalues存储存储并使用寄存器/只读存储器作为标量值
  • 将表达式标记为难以捉摸:rvalues不会长寿
    • 允许编译器在内部和c ++ 1x中有效的复制语义也暴露给程序员(参见移动语义和右值引用):我们可以从可能被销毁的rval中窃取资源.
  • 允许在该属性上构建规则
    • 不允许从左值所指的尚未初始化的对象生成rvalues.但是左值可以指未初始化的对象
    • rvalues永远不会是多态的.它们的静态类型也必须是它们的动态类型:简化typeid运算符的规则.

......还有更多,我觉得......


Nem*_*vic 8

我知道的最好的解释之一可以在这篇关于RValue参考的文章中找到.

确定表达式是否为左值的另一种方法是询问"我可以取其地址吗?".如果可以的话,这是一个左值.如果你做不到,这是一个左值.例如,&obj,&*ptr,&ptr [index]和&++ x都是有效的(即使其中一些表达式是愚蠢的),而&1729,&(x + y),&std :: string("喵" ")和&x ++都是无效的.为什么这样做?地址运算符要求其"操作数应为左值"(C++ 03 5.3.1/2).为什么需要呢?获取持久对象的地址是可以的,但是获取临时对象的地址会非常危险,因为临时对象会迅速消失.