2015-10-14 38 views
5
std::map<int,int> bar; 

int foo(int key) 
{ 
    bar.erase(key); 
    return 1; 
}  

int main() 
{ 
    bar[0] = foo(0); 
    return 0; 
} 

當使用電子圍欄檢查內存使用情況時,使用GCC 4.8編譯的代碼segs fault。C++ STL map :: operator []在被刪除的條目上完成

LD_PRELOAD=libefence.so.0.0 ./a.out 

的問題來自編譯器生成啓動分配在地圖上一個新條目的代碼,然後執行foo()去投入bar[0]價值的事實。在運行foo()時,條目被破壞,代碼最終通過寫入未分配的內存而結束。

操作的排序方式取決於編譯器實現,還是由C++當前標準指定?

+2

不要做.. –

+1

也http://stackoverflow.com/a/4183735見。 –

+0

研究序列和序列點。在'foo(0)'之前是否會對bar [0]'進行評估,如果是(它看起來像是你),那麼它是未定義的,那麼你就會遇到很大麻煩。 – AndyG

回答

5

標準(§1.915)中指定的兩個操作數的二進制操作的評價是未測序(除非在某些特定情況下):

除非另有說明,個體經營者 的操作數的評價和個人表達的子表達式是不確定的。

這意味着它並沒有要求賦值操作的一邊先於另一邊進行求值,事實上,這是未定義的行爲,取決於這些非序列操作的順序。

對於函數參數的求值順序,這也是正確的。

您需要打破你的兩個任務:

int result = foo(0); 
bar[0] = result; 
+0

「,事實上,這是不確定的行爲,取決於操作的順序」 - 它通常不是。這兩個函數調用的順序是未指定的,但這隻意味着不能可靠地確定首先調用哪個函數。恰巧在OP的情況下,根據順序,將訪問一個懸掛參考。 * *表現出未定義的行爲,而不是僅依賴於特定操作順序的事實。即使我想'printf(「Hello,」)+ printf(「world!」)'打印'Hello,world!',我保證可以輸出想要的結果或'world!Hello'。 – hvd

+0

@ hvd,是的,我的意思是UB取決於無序操作的順序。 – zneak

+0

哦,糟糕,術語混淆。由於函數調用,在我的例子和OP的代碼中,這是「不確定的排序」,而不是「無序的」。你仍然認爲這是UB嗎? – hvd