cout << a ++ << a;是什么答案?
最近在一次采访中,有一个客观types的问题。
int a = 0; cout << a++ << a; 回答:
 一个。  10 
 湾  01 
  C。 未定义的行为 
我回答了selectb,即输出将是“01”。
但是让我吃惊的是后来,一位面试官告诉我,正确的答案是选项c:undefined。
现在,我知道C ++中序列点的概念。 以下语句的行为未定义:
 int i = 0; i += i++ + i++; 
 但根据我对语句cout << a++ << a的ostream.operator<<() , ostream.operator<<()将被调用两次,第一次使用ostream.operator<<(a++)和后来的ostream.operator<<(a) 。 
我也检查了VS2010编译器的结果,它的输出也是'01'。
你可以想到:
 cout << a++ << a; 
如:
 std::operator<<(std::operator<<(std::cout, a++), a); 
  C ++保证以前评估的所有副作用将在序列点执行。 在函数参数评估之间没有序列点,这意味着参数a可以在参数std::operator<<(std::cout, a++)或之后求值。 所以上面的结果是不确定的。 
C ++ 17更新
在C ++ 17中,规则已被更新。 尤其是:
在移位算子expression式
E1<<E2和E1>>E2,E1每个值计算和副作用在E2每个值计算和副作用之前被sorting。
 这意味着它需要代码产生结果b ,输出01 。 
有关更多详细信息,请参阅P0145R3精炼expression式评估顺序以了解更多信息。
从技术上讲,总的来说这是未定义的行为 。
但是,答案有两个重要方面。
代码声明:
 std::cout << a++ << a; 
被评估为:
 std::operator<<(std::operator<<(std::cout, a++), a); 
 该标准没有定义函数参数的评估顺序。 
 所以: 
-   std::operator<<(std::cout, a++)首先被评估
-   a首先被评估或
- 它可能是任何实现定义的顺序。
这个订单是未指定的 [Ref 1]根据标准。
  [参考1] C ++ 03 5.2.2函数调用 
  第8段 
参数的评估顺序是未指定的 。 参数expression式评估的所有副作用在input函数之前生效。 未指定后缀expression式和参数expression式列表的评估顺序。
此外,在函数的参数评估之间没有序列点,但是只有在评估所有参数后才存在序列点[参考文献2] 。
  [参考2] C ++ 03 1.9程序执行[intro.execution]: 
  第17段: 
当调用一个函数(函数是否是内联函数)时,在执行函数体中的任何expression式或语句之前,所有函数参数(如果有的话)的求值之后都有一个序列点。
 注意,这里c的值正在被访问不止一次,没有一个中间的顺序点,对此标准说: 
  [参考3] C ++ 03 5expression式[expr]: 
  段落4: 
….
在前一个和下一个序列点之间,一个标量对象应该通过评估一个expression式来最多修改其存储值。 此外,只有在确定要存储的值时才能访问先前值 。 对于一个完整expression式的子expression式的每个可允许的sorting,应满足本段的要求; 否则行为是不确定的 。
 该代码不止一次修改c而不干涉顺序点,并且不被访问来确定存储的对象的值。 这明显违反了上述条款,因此标准规定的结果是未定义行为 [参考文献3] 。 
序列点只定义了部分sorting。 在你的情况下,你有(一旦重载parsing完成):
 std::cout.operator<<( a++ ).operator<<( a ); 
  a++和第一次调用std::ostream::operator<<之间有一个序列点,第二次调用和第二次调用std::ostream::operator<<之间有一个序列点,但是在那里在a++和a之间没有序列点; 唯一的sorting约束是在第一次调用operator<<之前a++被充分评估(包括副作用),第二a在调用operator<<之前被完全评估。  (也有因果顺序约束:第二次调用operator<<不能先于第一个,因为它需要第一个结果作为参数。)§5/ 4(C ++ 03)指出: 
除非另有说明,否则个体运算符的操作数和个别expression式的子expression式的评估顺序以及副作用发生的顺序是未指定的。 在前一个和下一个序列点之间,一个标量对象应该通过评估一个expression式来最多修改其存储值。 此外,只有在确定要存储的值时才能访问先前值。 对于一个完整expression式的子expression式的每个可允许的sorting,应满足本段的要求; 否则行为是不确定的。
 您的expression式的允许sorting之一是a++ ,首先调用operator<< ,第二次调用operator<< ; 这会修改a ( a++ )的存储值,并且除了确定新值(第二个a )外,还会访问它,所以行为是未定义的。 
正确的答案是质疑这个问题。 声明是不能接受的,因为读者看不到明确的答案。 另一种看待它的方法是我们引入了副作用(c ++),这使得陈述更加难以解释。 简洁的代码非常好,只要它的含义是明确的。