迭代器失效
原題
1 CONTAINER::iterator iter , tempIt; 2 for (iter = cont.begin() ; iter != cont.end() ; ) 3 { 4 tempIt = iter; 5 ++iter; 6 cont.erase(tempIt); 7 8 } 9 10 假設cont是一個CONTAINER的示例,里面包含數個元素,那么當CONTAINER為: 1、vector 2、list 3、map 4、deque 11 會導致上面的代碼片段崩潰的CONTAINER類型是? 答案:1,4 1. vector,erase(pos),直接把pos+1到finish的數據拷貝到以pos為起點的區間上,也就是vector的長度會逐漸變短(所有元素前移),而后iter會逐漸往后移動,直到iter == cont.end(),由于容器中end()返回的迭代器是最后一個元素的下一個(這個地方沒有任何值),現在考慮這個狀態前一個狀態,此時要刪除的點是iter, tempIt = iter, ++iter會指向此時的end(),但是執行erase(tempIt)之后,end()向前移動了!此時iter空了!!!不崩潰才怪。 2. list,erase(pos),干的事情很簡單,刪除自己,前后的節點連接起來就完了,所以iter自增的過程不會指空,不會崩潰嘍。 3. map,erase(pos),干的事情太復雜,但是我們需要知道的信息其實很少。該容器底層實現是RBTree,刪除操作分了很多種情形來討論的,目的是為了維持紅黑樹性質。但是我們需要知道的就是每個節點類似于list節點,都是單獨分配的空間,所以刪除一個節點并不會對其他迭代器產生影響,對應到題目中,不會崩潰嘍。 4. deque,erase(pos),與vector的erase(pos)有些類似,基于結構的不同導致中間有些步驟不太一致。先說說deque的結構(這個結構本身比較復雜,揀重要說吧,具體看STL源碼),它是一個雙向開口的連續線性空間,實質是分段連續的,由中控器map維持其整體連續的假象。其實題中只要知道它是雙向開口的就夠了(可以在頭部或尾部增加、刪除)。在題中有erase(pos),deque是這樣處理的:如果pos之前的元素個數比較少,那么把start到pos-1的數據移到起始地址為start+1的區間內;否則把pos后面的數據移到起始地址為pos的區間內。在題中iter一直往后移動,總會出現后面數據比前面少的時候,這時候問題就和1一樣了,必須崩潰! 總結:關聯容器(如map, set, multimap,multiset),刪除當前的iterator,只會使當前的iterator失效,只要在erase時,遞增當前iterator即可。對于序列式容器(如vector,deque),刪除當前的iterator會使后面所有元素的iterator都失效。這是因為vetor,deque使用了連續分配的內存,刪除一個元素導致后面所有的元素會向前移動一個位置,位于該元素之前位置的迭代器不會失效。不過erase方法可以返回下一個有效的iterator,cont.erase(iter++)可以修改為cont.erase(iter) 而list使用了不連續分配的內存,并且它的erase方法也會返回下一個有效的iterator。轉載于:https://www.cnblogs.com/coding-wtf/p/5771177.html
總結
- 上一篇: cc笔记_robotium_01
- 下一篇: 响应式开发中合理选定CSS媒体查询分割点