前缀和后缀运算符的奇怪行为

时间:2013-11-01 15:13:42

标签: c++ compiler-construction standards

为什么第一个表达式允许,但第二个表达式不允许:

void test()
{
   int a;

   ++a = getSomeInt();
   a++ = getSomeInt();
}

我的意思是,为什么禁止第二个成为 lvalue ?第二个是有道理的,第一个没有。在第一个我们增加变量,并在我们给这里一个新值后立即失去它。在第二个表达式中并非如此。在此之后分配一些值并增加变量是有意义的。

1 个答案:

答案 0 :(得分:7)

后缀增量的结果是 prvalue ,这意味着pure rvalue所以它不可修改。这是draft C++ standard后缀表达式部分5.2.6 增量和减量,它表示(强调我的):< / p>

  

后缀++表达式的值是其操作数的值。 [注意:获得的值是原始值的副本 -end note] [...] 结果是prvalue 。 [...]

如果您考虑它,这是有道理的,因为您需要返回先前的a值,它必须是临时值。

为了完整起见,5.3.2 部分中前缀增量的语言增量和减量表示(强调我的):

  

前缀++的操作数通过添加1来修改,或者如果它是bool则设置为true(不推荐使用此用法)。 操作数应为可修改的左值。操作数的类型应为算术类型或指向完全定义的对象类型的指针。 结果是更新的操作数;这是一个左值 [...]

更新

我意识到:

++a = getSomeInt();

C ++ 03 中调用undefined behavior,我们可以看到older draft standard中的相关部分是5 部分表达式段落 4 ,其中包含:

  

[...] 在上一个和下一个序列点之间,标量对象的表达式评估最多只能修改一次的存储值。此外,只能访问先前值以确定要存储的值。对于完整表达式的子表达式的每个允许排序,应满足本段的要求; 否则行为未定义。

因为您修改 a不止一次未定义。据我所知,这在 C ++ 11 中有明确定义,在1.9 部分中,程序执行 15 表示:

  

除非另有说明,否则对单个运算符的操作数和单个表达式的子表达式的评估是不确定的。 [...] 如果对标量对象的副作用相对于同一标量对象的另一个副作用或使用相同标量对象的值进行的值计算未被排序,则行为未定义。

我们可以在5.17 部分和复合赋值运算符 1 中看到:

  

[...]在所有情况下,赋值在右和左操作数的值计算之后,以及赋值表达式的值计算之前排序。 [...]

但无论如何,即使它是定义良好的表达式,如下所示:

++a = getSomeInt();

难以阅读和维护,应该避免使用更简单的代码。

更新2

不确定我是如何错过这个但是你没有在这里初始化a

 int a;

因此它将具有不确定值,我们不知道它的初始值是什么,并且在a上执行预增量也是未定义的行为