c ++ - 为什么++ x是左值而x ++是右值?

这个问题在这里已有答案:

  • 前/后增量的左值和右值                                     1个答案

所以我一直在阅读左值和左值,我对++xx++之间的差异感到有些困惑。

为什么++x是左值,而x++是左值?

samuelnj asked 2019-08-13T17:42:37Z
6个解决方案
108 votes

++x返回对您递增的对象的引用,其中x++返回x的旧值的临时副本。

至少这将是"正常" 按惯例实现这些运算符的方法。 所有内置类型都以这种方式工作。 如果您已经阅读了左值/右值,那么您会看到,因为前缀运算符返回命名对象本身它将是一个左值,其中后缀运算符返回本地临时值的副本,然后它将符合条件 一个右值。

注意:此外,我们现在有prvalues,xvalues等,所以现在它在技术上有点复杂。 在这里查看更多信息。

Carl answered 2019-08-13T17:43:06Z
45 votes

C ++(而不是C语言)是一种专注于左值的语言:它努力保持"左值" 只要有可能就表达出来。

  • 保持"左值"非常容易。 预增量:只需增加操作数并将其作为左值返回。完成。 返回的左值将包含它应该包含的结果:操作数的新(递增)值。

  • 同时,几乎不可能保持"左值" 后增量:根据定义,后增量的结果是操作数的旧(原始)值。 如果你试图从后增量中返回一个左值,你将不得不以某种方式同时确保两件事:1)左值增加,2)调用代码在查看相同的左值(!)时看到旧值。 这种要求的组合是如此矛盾,基本上不可能在C ++对象模型中实现。

    为了实现适当的后增量行为,必须确保调用代码不直接查看操作数,而是查看一些概念或物理"代理" 这使得调用代码变为"看到" 操作数的旧值。 该代理可能是一个保存旧值的临时对象。 或者该代理可能是通过从新值中减去1来动态生成旧值的代理。 在任何情况下,该代理都会阻止调用代码访问原始左值。

这就是为什么C ++利用容易实现的机会来保持" lvalueness" 预增量,但承认不可能通过后增量实现相同的增量。 在后增量的情况下,不值得努力偏离经典标准C行为,这往往会丢弃" lvalueness" 快乐而愉快。

AnT answered 2019-08-13T17:44:05Z
29 votes

也许用int的运算符的伪代码写下工作原理会更清楚:

字首:

int& Prefix(int& val)
{
  int& value = val;
  value += 1;
  return value;
}

后缀:

int Postfix(int& val)
{
  int oldValue = val;
  val += 1;
  return oldValue; 
}

不同之处在于两个运算符返回的值,一个是值,一个是引用。

Sombrero Chicken answered 2019-08-13T17:44:52Z
14 votes

为什么++ x是左值

我猜这是一个左值,因为它可以。

x++它可以被认为是

((x = x + 1), x)  // Increment x. Then evaluate to the value of x

要么

((x += 1), x)    //  Increment x. Then evaluate to the value of x

x++评估为左值是有意义的。

x ++一个右值?

因为它不是左值。

x++它可以被认为是

((unnamed_variable = x), (x = x + 1), unnamed_variable)

要么

((unnamed_variable = x), (x += 1), unnamed_variable)

x++评估为x之前的值递增。 由于没有可以存储该值的变量,因此它不能是左值。

R Sahu answered 2019-08-13T17:46:05Z
11 votes

对于内置类型,例如++x,x,产生旧值x.没有与此关联的存储,因此表达式不可能是左值。

在C中,++x产生了新值x(并且不是左值)。 由于对象x实际上包含相同的值,因此可以使++x指定对象x(即,是左值)。 与产生右值相比,这是增加的功能,C ++的设计者认为这将是对语言的改进。

对于类类型,可以使任何运算符重载,使得运算符的使用可以产生左值,x值或初值。 然而,使重载运算符具有与内置运算符类似的语义被认为是好的风格,这就是为什么人们过载++x以产生左值并且过载x++以产生右值是正常的。

M.M answered 2019-08-13T17:46:50Z
9 votes

首先,一个"左值" 是一个在左侧合法的表达式(" l"在"左值"中)是一个合法的表达式。 这意味着它代表一个地址,其内容可以通过赋值来改变。 (C标准称这样的东西为"对象"。)这就是为什么,例如,中缀运算符表达式和函数调用不是左值。

"右值" 是一个愚蠢的术语; 任何格式良好的表达式在赋值的右侧是合法的(保留类型转换问题)。

标准说,例如:

i = ++i + 1;
a[i++] = i;

..两个"未定义的语句表达式",意味着它们的实现(因此行为)不是标准化的。

" ++ i"的常识含义 是"增加对象i的值,并计算结果"。 同样," i ++" 表示"评估对象i的当前值,然后递增对象的值"。 也没有说出当" ++ i" 或" i ++" 用作左值。

标准说,关于表达式:"运算符的操作数的值计算在运算符的结果的值计算之前被排序。" 这对于" ++ i"实际上是模糊的,因为操作数的值计算受运算符的值计算的影响。

对我来说最有意义的是:

i = 5;
++i = i + 1;   /*i is set to 6*/
i++ = 1;       /*i is set to 1*/
++i = ++i + 1; /*i is set to 8, but problematic*/
i++ = i++ + 1; /*i is set to 8, but problematic*/
++i = i++ + 1; /*i is set to 8, but problematic*/

我的建议 - 不要使用那些难以理解的表达方式!

Stephen F. Heffner answered 2019-08-13T17:48:09Z
translate from https://stackoverflow.com:/questions/50802859/why-is-x-a-lvalue-and-x-a-rvalue