代码之家  ›  专栏  ›  技术社区  ›  samuelnj

为什么+x是左值,x++是右值?[复制品]

  •  92
  • samuelnj  · 技术社区  · 7 年前

    这个问题已经有了答案:

    所以我一直在读左值和右值,我有点困惑 ++x x++ 当涉及到这个分类时。

    为什么是 +x 一个傻瓜 x++ 一个价值?

    6 回复  |  直到 7 年前
        1
  •  108
  •   Carl    7 年前

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

    至少这是按惯例实施这些运营商的“正常”方式。所有内置类型都是这样工作的。如果你读过关于左值/右值的内容,你会发现由于前缀运算符返回命名对象本身,它将是一个左值,其中作为后缀运算符返回一个本地临时值的副本,然后它将被限定为一个右值。

    注:还有,我们现在有prvalues,xvalues等等,所以现在技术上比较复杂。看 here for more info.

        2
  •  45
  •   AnT stands with Russia    7 年前

    C++(与C相反)是一个专门的 保留左值 语言:只要有可能,它都会努力保持表达式的“左值”。

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

    • 同时,几乎不可能保持 后增操作 :根据定义,后增量的结果是操作数的旧(原始)值。如果试图从post increment返回左值,则必须同时确保两件事:1)左值递增,2)调用代码看到 古老的 当它查看相同的左值时的值(!)这种需求的组合是如此矛盾,基本上不可能在C++对象模型中实现。

      为了实现正确的增量后行为,必须确保调用代码不直接查看操作数,而是查看一些概念上或物理上的“代理”,使调用代码“查看”操作数的旧值。该代理可能是保存旧值的临时对象。或者代理可能会产生旧的值 苍蝇 减去 1 从新的价值观。无论如何,代理是阻止调用代码访问原始左值的原因。

    这就是为什么C++利用容易实现的机会来保持预增量的“轻量级”,但承认在后增量中实现同样的可能性是不可能的。在后增量的情况下,偏离经典的标准c行为是不值得的,它倾向于快速愉快地抛弃“左值性”。

        3
  •  29
  •   anatolyg    7 年前

    也许用伪代码写下 int 更清楚地说:

    前缀:

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

    后缀:

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

    区别在于两个运算符返回的内容,一个是值,一个是引用。

        4
  •  14
  •   R Sahu    7 年前

    为什么++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 是递增的。因为没有可以存储该值的变量,所以它不能是一个LValk。

        5
  •  11
  •   M.M    7 年前

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

    在C中, ++x 产生了 X (而不是一个左值)。因为这个物体 X 实际上包含相同的值 +x 指定对象 X (即成为左值)。这是增加了功能的比较,以产生一个超链接,而设计师的C++决定这将是一个改进的语言。

    对于类类型 可以使用操作符来生成LValk、XValuy或PROVE来重载任何操作符。然而,让重载运算符具有与内置运算符相似的语义被认为是一种好的方式,这就是为什么人们重载是正常的 +x 产生左值并过载 x++ 产生右旋值。

        6
  •  9
  •   Stephen F. Heffner    7 年前

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

    “rvalue”是一个愚蠢的术语;任何格式良好的表达式在赋值的右侧都是合法的(不考虑类型转换问题)。

    标准规定,例如:

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

    …都是“未定义的语句表达式”,这意味着它们的实现(因此行为)不标准。

    “++i”的一般意义是“增加对象i的值,并对结果求值”。类似地,“i++”表示“对对象i的当前值求值,然后增加对象的值”。也没有说明当“++i”或“i++”用作左值时会发生什么。

    标准的about表达式是这样说的:“运算符的操作数的值计算在运算符结果的值计算之前进行排序。”因为操作数的值计算受运算符的值计算的影响。

    对我来说最有意义的是:

    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*/
    

    我的建议是——不要用那么难理解的表达方式!