在使用vector的過程中,有時會遇到需要迴圈遍歷vector,並刪除符合指定條件的元素。
當「指定條件」不複雜時,應該盡量使用erase(remove_if(begin, end, func), end)的形式來完成功能。
但有時候「指定條件」過於複雜,不得不顯式地寫乙個for迴圈來處理。我們必須小心在意erase所帶來的side effect,乙個一般性的for迴圈如下:
1for (std::vector::iterator it = intvec.begin(); it != intvec.end(); /**/
)
2
7else
8
11 }所要注意的是it = intvec.erase(it)。實際上這裡如果寫成intvec.erase(it),即不對it做重新賦值,**也能正常執行,特別是release版本幾乎所有的編譯器編譯後都能產生結果正確的**。而debug模式下有一些較新的編譯器會在編譯時給出警告,並在執行時出現斷言錯誤。
為什麼乙個錯誤的寫法在大多數情況下都能得到正確的答案?
根據stl的描述,執行erase(it)後,it和it之後的迭代器都可能會失效。這一點很好理解。因為vector一般由動態陣列實現,它的元素在記憶體中是連續儲存的。當刪除掉it所指向元素時,原本在it後面的元素需要集體前移。迭代器本身幾乎可以理解為是乙個指標,在erase之後它所指向的位置並沒有變化,只是那個位置的元素發生了變化,而且恰好變成了我們所想要的。至少大多數stl版本是這麼實現的,因為這處理起來比較自然。
然而我們不能依賴於這個一般性事實,而應該採用it=intvec.erase(it)的形式來對it重新賦值。stl中有要求vector的erase函式要返回指向被erase的迭代器的下乙個位置,寫成it=intvec.erase(it)是萬無一失的,而寫成intvec.erase(it)雖然實際可行,但是具有潛在風險,萬一某一天erase會影響it的指向(stl只要求erase移除元素,而沒***it自身不變),程式就極有可能出問題。
根據標準所描述的約束來程式設計,而不是根據具體的實現細節來程式設計。
對於c++ stl,似乎有很多個版本的實現,而它們或多或少都有所偏差。這裡有兩個**,可以進行參考:和
最初犯了這樣的錯誤:
for(vector::iterator it=m_stgestureinfo.begin(); it != m_stgestureinfo.end(); /*it++*/)
pcurrtraj= pcurrtraj->getnext();
}if(false == bsameflag)
it = m_stgestureinfo.erase(it);
if(it == m_stgestureinfo.end()) //要控制迭代器不能超過整個容器 }
這樣導致,每次刪除後,刪除的後乙個元素不參與判斷。因為erase之後,後面的元素會移位,此時it指向另外刪除後面的元素,然後it++,最後會導致刪除後面的元素被跳過,因此
正確寫法:
for(vector::iterator it=m_stgestureinfo.begin(); it != m_stgestureinfo.end(); /*it++*/)
pcurrtraj= pcurrtraj->getnext();
}if(false == bsameflag)
it = m_stgestureinfo.erase(it);
else
it++;
}
在vector的迴圈中呼叫erase
在使用 vector的過程中,有時會遇到需要迴圈遍歷vector,並刪除符合指定條件的元素。當 指定條件 不複雜時,應該盡量使用erase remove if begin,end,func end 的形式來完成功能。但有時候 指定條件 過於複雜,不得不顯式地寫乙個for迴圈來處理。我們必須小心在意e...
在vector的迴圈中呼叫erase
在使用 vector 的過程中,有時會遇到需要迴圈遍歷 vector 並刪除符合指定條件的元素。當 指定條件 不複雜時,應該盡量使用 erase remove if begin,end,func end 的形式來完成功能。但有時候 指定條件 過於複雜,不得不顯式地寫乙個 for迴圈來處理。我們必須小...
js迴圈中呼叫ajax
var i for i 0 i 10 i 在for迴圈中呼叫ajax方法 補充頁面上的資料,這樣寫是錯誤的,他不會每執行一次for迴圈就執行一次ajax方法,而是等for迴圈結束才去執行ajax方法,所以導致ajax只被執行一次。然而當修改如下 for i 0 i 10 i 與上面不同的是在每次呼叫...