2012-02-16 107 views
2

我很困惑。我學到或被告知的是,如果調用擦除,則向量的迭代器將變爲無效。但爲什麼下面的代碼工作。它使用g ++編譯並在Linux中運行。調用擦除後迭代器無效

#include <vector> 
#include <iostream> 

using namespace std; 

int main() { 
    vector<int> vec; 
    vec.push_back(1); 
    vec.push_back(2); 
    vec.push_back(3); 

    vector<int>::iterator it = vec.begin(); 
    ++it; 
    vector<int>::iterator it2; 

    it2 = vec.erase(it); 
    cout << "it: " << *it << endl; 
    cout << "it2: " << *it2 << endl; 
} 

感謝您的任何反饋!

+2

它「有效」,即它顯示UB沒有明顯的症狀。 – PlasmaHH 2012-02-16 11:13:41

+0

定義「代碼工程」。做你所期望的是一個可能的結果_ [未定義的行爲](http://stackoverflow.com/a/1553407/140719)_。 – sbi 2012-02-16 11:15:13

+0

當你使用gcc時,試着用'-D_GLIBCXX_DEBUG'運行,你就會開悟。希望。 – PlasmaHH 2012-02-16 11:18:48

回答

2

http://www.cplusplus.com/reference/stl/vector/erase/(未世界上最好的C++參考):

這會使所有迭代器和參考位置(或第一)和其隨後的元件。

所以it無效;使用它會導致未定義的行爲。事實上,你碰巧得到你所期望的是純粹的運氣不好。

+1

其實,我會叫它_bad_運氣。當它立即崩潰時你很幸運,因爲那時你意識到有什麼事情是相反的。 ':)' – sbi 2012-02-16 11:16:37

+0

thx您的反饋。我想了想,但卻無法相信它發生了。 – Orunner 2012-02-16 11:17:14

1

你在做什麼是未定義行爲,並認爲它「作品」完全是偶然的。你不能也不可以永遠依靠這個,因爲它可以做任何事情。它的行爲沒有定義。

0

作爲實施細節,vector<int>::iterator可以很容易地爲int*。我認爲在g++這是一個非常薄的包裝圍繞int*。如果是這樣的話,那麼擦除三元素向量的中間元素意味着it的指針數據成員被指向與被刪除的元素相同的地址,這當然將包含先前在其之後的值,並且其也由it2有效地提及。

標準並不保證it仍然會引用任何內容,這就是爲什麼你不能依賴你在這裏觀察到的行爲。但它解釋了你所看到的。當你取消引用it時,一個實現幾乎不得不使其他方式發生。但編譯器每天都會走出困境:例如,調試庫的版本,並且一些優化技術依賴於假設您的代碼是正確的。