2011-11-28 74 views
8
int& foo() { 
    printf("Foo\n"); 
    static int a; 
    return a; 
} 

int bar() { 
    printf("Bar\n"); 
    return 1; 
} 

void main() { 
    foo() = bar(); 
} 

我不確定首先應該評估哪一個。賦值運算符中的C++函數評估順序

我試過在VC中先執行bar函數。然而,在g ++(FreeBSD)編譯器中,它首先給出了foo函數。

許多有趣的問題是從上述問題衍生,假設我有一個動態陣列(標準::矢量)

std::vector<int> vec; 

int foobar() { 
    vec.resize(vec.size() + 1); 
    return vec.size(); 
} 

void main() { 
    vec.resize(2); 
    vec[0] = foobar(); 
} 

根據以往的結果是,VC評估foobar的(),然後執行矢量操作符[]。在這種情況下這沒有問題。但是,對於gcc,由於正在評估vec [0],並且foobar()函數可能會導致更改數組的內部指針。在執行foobar()之後vec [0]可以失效。

是不是意味着我們需要單獨的代碼,這樣

void main() { 
    vec.resize(2); 
    int a = foobar(); 
    vec[0] = a; 
} 
+3

+2,這是一個有趣的問題;這是我以前從未考慮過的事情。顯然,如果你開始使用類似的代碼,你會遇到麻煩:) –

+0

+1。這真是一個有趣的問題;更重要的是這個問題被問得很好。一個寫得很好的問題。 – Nawaz

+1

我今天遇到了一個有趣的例子:'auto_ptr p(new int); smart_map m; m [1] = p.release();'如果你認爲'smart_map :: operator []'可能被拋出,你可能會遇到'auto_ptr'釋放它的所有權的情況,但是map永遠不會承擔所有權,在LHS之前評估RHS的情況。 (假設'smart_map'就像一個STL'map',除了刪除銷燬時每個鍵/值對的指針值。) – mrkj

回答

8

訂單評價將是在這種情況下指定。不寫這樣的代碼

類似的例子here

0

的表達式的求值的順序是未指定的行爲
它取決於編譯器選擇評估它的順序。

你應該避免寫shuch代碼。
雖然如果沒有副作用,那麼順序應該不重要。

如果訂單的問題,那麼你的代碼是錯誤/不可移植/可能會給出不同的結果翻過不同的編譯器**。

5

管理評估順序是否定義的C++中的概念被稱爲sequence point

基本上,在一個序列點上,確保所有在該點之前的表達式(具有可觀察的副作用)已經被評估,並且沒有超出該點的表達式被評估。

雖然有些人可能會覺得很驚訝,但賦值運算符並不是一個序列點。所有序列點的完整列表位於Wikipedia article

+2

... _was_叫做序列點。今年以來,我們使用_sequenced before_/_sequenced after_。 – MSalters

+0

@ MSalters:謝謝你指出 - 不知道! –