分配中的表达评估

时间:2011-12-06 14:23:16

标签: c++

我很惊讶地发现,在GCC(4.3.2)中,可以在右侧之前评估赋值表达式的左侧:

int x,y;

int& getX()
{
  std::cout << "getX\n";
  return x;
}

int& getY()
{
  std::cout << "getY\n";
  return y;
}

void test()
{
  x = 3; y= 4;
  getX() = getY();
}

调用test()输出

getX
getY

而在MSVC上,使用相反的顺序。标准是否有关于此的定义?

4 个答案:

答案 0 :(得分:5)

是和否。

本质上,标准定义它是未指定的,并且只保证在调用函数时参数将准备就绪。

编辑:更糟糕的是,表达式评估可能是交错的。参见示例。

基本上你应该记住,只要你有一个函数,并且a = b是函数调用:operator=(a , b),那么函数的参数的计算顺序是未指定的。

GCC通常从右到左,但优化器可以决定有时从左到右比较快。它甚至可以在运行时更改,但由于实际原因,我从未见过这样的实现。

修改

由于标准不承诺特定的排序甚至原子执行,因此以下声明:

test(foo() + bar(), fud());

可以产生以下4个呼叫序列:

  • foo,bar,fud
  • bar,foo,fud
  • fud,foo,bar
  • fud,bar,foo

当您理解“未指定”术语及其后果时,或多或少“预期”......但它也可能导致以下两个序列:

  • foo,fud,bar
  • bar,fud,foo

更令人惊讶。这是交错的。

我在此处遗漏了+操作,该操作只能在计算foobar后执行,但可以在fud之前或之后执行。

如果函数是纯函数,或者具有完全不相交的操作集,则无关紧要。有时会出现一些令人惊讶的副作用,甚至可能导致内存泄漏......

答案 1 :(得分:2)

标准没有指定评估顺序,这意味着实现可以选择它想要的任何顺序。

答案 2 :(得分:2)

赋值运算符=着名的不是在C ++ 98/03中引入序列点,或者在C ++ 11中,任何一方的表达式都没有相互排序。

答案 3 :(得分:2)

根据规范

,未指定operator =的操作数评估顺序
  

除非另有说明,否则单个运算符的操作数和个别表达式的子表达式的评估顺序以及副作用发生的顺序是未指定的。