2009-06-15 54 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

除非另有說明, 評估個體 運營商和 單個表達式的子表達式的操作數,並 其中副作用採取的順序的順序地方,是 不確定