int i = 0; foo(++ i,++ i,++ i);定义明确?

时间:2017-04-03 12:58:31

标签: c++ c++17

如果我正确理解了C ++ 17标准,那么函数参数应该是不确定的顺序(P0145R3)。 请考虑以下测试用例:

#include <stdio.h>
void foo(int a, int b, int c) { printf("%d %d %d\n", a, b, c); }
int main() {
  int i = 0;
  foo(++i, ++i, ++i);
}

clang警告不正确:

  

警告:对&#39; i&#39;进行多次无序修改[-Wunsequenced]

并打印:1 2 3

gcc也警告说:

  

警告:'i'上的操作可能未定义[-Wsequence-point]

并打印:3 3 3

哪个输出正确?

1 个答案:

答案 0 :(得分:0)

根据C ++ 17 5.2.2 / 4中的注释,函数参数的初始化未被排序:

  

调用函数时,应初始化每个参数(8.3.5)(8.5,12.8,12.1)及其对应的参数   论点。 [注意:这种初始化相对于彼此不确定地排序(1.9) -   结束说明]

这意味着即使函数参数保证从左到右进行评估(我无法在C ++ 17草案中找到任何信息),参数的初始化仍然是不确定的顺序。

这意味着,例如,如果您的参数都调用相同的复制构造函数,而后者又修改了全局/静态资源,则您的程序具有未指定的行为:

static int f;

Foo::Foo (const Foo& foo)
  : x(f++)
{}

...

void func (Foo a, Foo b, Foo c)
{
  std::cout << a.x << b.x << c.x;  // unspecified output
}

一个好的编译器会在发现依赖于未指明的行为=确定性但未记录的行为时给出警告,你不能假设这些行为。