在使用
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迴圈來處理。我們必須小心在意er...
在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 與上面不同的是在每次呼叫...