2010-03-29 87 views
3

鑑於後增量運算符的評估按什麼順序發生?

std::vector<CMyClass> objects; 
CMyClass list[MAX_OBJECT_COUNT]; 

是否明智做到這一點?

for(unsigned int i = 0; i < objects.size(); list[i] = objects.at(i++)); 

或者我應該擴大我的循環?

for(unsigned int i = 0; i < objects.size(); i++) 
{ 
    list[i] = objects.at(i); 
} 
+0

哪些類型做'list'和'objects'有哪些? – MSalters 2010-03-29 15:33:28

+0

我更新了我的問題以反映這一點。 – sum1stolemyname 2010-03-30 05:29:04

回答

11

前者是未定義的行爲。在函數調用objects.at之前或之後,沒有指定是否對list[i]進行評估(以便爲作業的lhs提供左值)。

因此,表達式的各個部分都有一個合法的排序,其中i被訪問(在list[i]中)並且被單獨修改(在i++中),沒有插入序列點。

這恰恰是C++標準中未定義行爲的條件 - 是否存在這樣的合法排序。 IIRC C標準表示略有不同,但具有相同的效果。

如果有疑問,不要寫一個使用增量運算符的表達式,並且在表達式的任何其他位置使用相同的值。你可以用逗號運算符(i++, i++罰款)和條件運算符(i ? i++ : i--罰款)來完成它,因爲它們中有序列點,但它很少值得。 ||&&,而類似p != end_p && *(p++) = something;的東西並不完全不合情理。任何其他用途,如果你盯着它足夠長的時間,你通常可以制定一個評估順序來排除干擾。

這不包括複雜的for表達式和for帶有空體的循環的可理解性。

+1

&&和||也是序列點(假設沒有超載) – 2010-03-29 14:43:02

+0

現在,在前面提到的for循環中使用它們會使它非常有趣。 – 2010-03-29 14:50:58

+0

-1。 Un **定義**行爲?不確定,當然。在您正確解釋時有兩種可能的順序,並且該標準不需要實現來記錄在什麼時候使用哪一個。但是這個標準並沒有把每一個細節都定義爲「未定義的行爲」。這是一個更糟糕的情況,其中包括徹底崩潰和惡魔。 – MSalters 2010-03-29 14:54:42

6

有疑問時,更喜歡哪更容易理解(展開環)的形式。

(我認爲list[i] = objects.at(i++)導致不確定的行爲。)

+0

它確實。我試過了。 – sum1stolemyname 2010-03-29 14:27:11

1

參考ii++的表達式可能是未定義的行爲。但是,因爲它看起來像你使用的容器,可能你也許正如有人已經說過,遞增後在使用它的產量不確定的行爲同樣表達一個變量寫...

list = objects;        // if they're the same type 
list.assign(objects.begin(), objects.end()); // if not 
+1

或者在最壞的情況下使用std :: copy,如果這兩個選項都不可用(比如list是一個C數組?)。 – 2010-03-29 15:12:55

1

。 但是,如果你想保持緊湊的形式,你可以引入一個序列點,去

for(unsigned int i = 0; i < objects.size(); list[i] = objects.at(i), i++); 
+0

這看起來像舊的「每個程序都可以編碼爲循環體」。 – Gorpik 2010-03-29 14:44:35

+0

不是嗎?我記得這個表格經常在IOCCC中使用...... – 2010-03-29 14:49:52