2009-06-15 49 views
4

考虑下面的代码:C++移算符优先古怪

typedef vector<int> intVec; 

intVec& operator<<(intVec& dst, const int i) { 
    dst.push_back(i); 
    return dst; 
} 
int intResult0() { 
    return 23; 
} 
int intResult1() { 
    return 42; 
} 

// main 
intVec v; 
v << intResult0() << intResult1(); 

奇怪的是,编译器生成的代码,其评估intResult1BEFOREintResult0(与最新VC UND GCC测试)。 为什么编译器会这样做?通过这样做,各个值的评估和使用之间的时间(不必要地)增加(?),即首先获取42,但最后被推到矢量上。 C++标准是否规定了这一点?

+0

嘿,我只是碰到了这个昨晚与运营商+ = ŧ他让我感到困惑的是,读取代码时,您会期望intResult1必须被第二次调用,因为它使用intResult0返回的值作为它的第一个参数。 – Dolphin 2009-06-15 16:25:00

回答

12

根据Stroustrup的节6.2.2:

的 子表达式评估的表达式中的顺序是 未定义。

10

这与优先顺序无关。

在最后一条语句中没有顺序点,所以只要在组合子表达式时使用优先级,编译器就可以按照它喜欢的顺序自由地评估子表达式。

请注意,优先级确定而不是定义了评估的整体顺序 - 它只是定义了如何组合具有多个运算符的表达式的操作数。

例如,在下面的表达式:

a() * b() + c() 

在某些时候,编译器将需要在c()结果将之前评估(a() * b()),但没有什么,说什么样的顺序每个独立的功能调用需求被制造。编译器可以很容易地决定先调用c(),然后将结果推送到堆栈上,然后执行需要做的任何操作来评估(a() * b())表达式(在这种情况下,它可能决定先评估b())。

该优先播放的唯一作用是,编译器是不允许的计算表达式为:

a() * (b() + c()) 
14

2个序列点之间的子表达式的评价的顺序是不确定的。

上面的代码语法糖:

v.operator<<(intResult0()).operator<<(intResult1()); 

唯一的约束,编译器,是它必须评估所有的参数被称为方法之前,服从优先规则。但只要遵循这些规则,每个实现都可以选择细节,因此这个顺序可能会在编译器之间改变。

在这个例子中:

  • 所以这是完全合法的调用intResult2前intResult1()()。
  • 但intResult0()必须在调用operator < <(之前被调用)(左)
  • 和intResult1()必须在调用operator < <(之前被调用)(右)
  • 和运营商< <()(左)之前必须称为运营商< <()(右)

这里看到更多的信息:
What are all the common undefined behaviours that a C++ programmer should know about?

What are all the common undefined behaviours that a C++ programmer should know about?

2

C++标准,5:4

除非另有说明, 评估个体 运营商和 单个表达式的子表达式的操作数,并 其中副作用采取的顺序的顺序地方,是 不确定