2015-10-25 37 views
0

考慮下面的代碼:行爲前增量運營商

#include <iostream> 
#include <vector> 
using namespace std; 

int main(int argc, char **argv) { 
    vector<int> v = { 1 }; 
    auto it = v.begin(); 
    cout << ++(*it) << " " << v[0] << " " << endl; 
    cout << v[0] << endl; 
    return EXIT_SUCCESS; 
} 

編譯和運行之後,此代碼產生了以下控制檯輸出:

2 1 
2 

鑑於++(*it)遞增第一矢量值,我會而是期望以下輸出:

2 2 
2 

爲什麼是不是v[0]的第一個cout聲明中反映的增量?

+0

在應用++運算符的表達式中沒有定義的序列點。 – EJP

+0

我無法弄清楚爲什麼有人會低估我的問題? –

回答

2

的原因是,:

cout<<++(*it); 

正在打印的下一個值2但只有後的線V增加原始值:

cout<<++(*it)<<" "<<v[0]<<" "; // v[0] is still `1` 

現在值v[0]遞增,並且結果是2

cout<< v[0]<<" "; 

你可以增加前cout

++(*it); 
cout<<*it<<" "<<v[0]<<" "; 

現在輸出將是相同的。

+0

[Clang disagrees](http://coliru.stacked-crooked.com/a/950eed02a0730246):) – melak47

1

++(*it)將遞增並返回元素it引用,而不是迭代器本身,所以v[0]2後評估該表達式。

那麼爲什麼不打印222? 由於operator<< S中的鏈實際上是嵌套函數調用,有點像這樣:

operator<<(operator<<(operator<<(operator<<(std::cout, ++(*it)), " "), v[0]), " ");

和感興趣的位:

operator<<(operator<<(std::cout, ++(*it)), " "), v[0])

這是一個函數調用有兩個參數, operator<<(std::cout, ++(*it))v[0]。 未指定函數參數的評估順序,一個平臺或編譯器可能與另一個平臺或編譯器做的不同(根據我所知,從左到右和從右到左是常見的)。

如果首先評估第二個參數,v[0]仍然保存在1中,我們打印212

如果首先評估第一個參數,則首先發生++(*it),然後檢索v[0],因此我們打印222

不幸的是,C++標準只能保證所有參數的評估在函數體之前排序,而不是相對於對方排序。

在未測序表達式同時使用v[0]++v[0]可以調用未定義行爲 - 它可以做你想要什麼,或者發射導彈。

+0

你是對的事實,它實際上是一個重載的函數調用,並且沒有關於參數評估的保證。但是這給了我另外一個疑問,那麼<<運算符的左結合性概念是什麼意思呢?(重載的<<也是左結合的)。不應該保留關聯性,以確保首先評估第一個參數? –

+0

@TarunBhargava左關聯只意味着像'((a << b)<< c)'這樣的'a << b << c'組和像'='這樣的右關聯運算符像((a = b =(c = 4)))' – melak47