疊代器(iterator)是一個可以對其執行類似指針的操作(如:解除引用(operator*())和遞增(operator++()))的對象,我們可以将它了解成為一個指針。但它又不是我們所謂普通的指針,我們可以稱之為廣義指針,你可以通過sizeof(vector::iterator)來檢視,所占記憶體并不是4個位元組。
如下圖所示:

這裡我們定義了一個vector疊代器,對其求sizeof(),發現是12個位元組,并不是一個指針的大小。那麼我們常說的疊代器失效到底是什麼呢?都有哪些場景會導緻失效問題呢?我們一起來看以下具體場景及解決辦法。
對于序列式容器,例如vector、deque;由于序列式容器是組合式容器,當目前元素的iterator被删除後,其後的所有元素的疊代器都會失效,這是因為vector,deque都是連續存儲的一段空間,是以當對其進行erase操作時,其後的每一個元素都會向前移一個位置。
運作結果,程式終止:
已經失效的疊代器不能進行++操作,是以程式中斷了。不過vector的erase操作可以傳回下一個有效的疊代器,是以隻要我們每次執行删除操作的時候,将下一個有效疊代器傳回就可以順利執行後續操作了,代碼修改如下:
這樣删除後it指向的元素後,傳回的是下一個元素的疊代器,這個疊代器是vector記憶體調整過後新的有效的疊代器。此時就可以進行正确的删除與通路操作了。
上面隻是舉了删除元素造成的vector疊代器失效問題,對于vector的插入元素也可以同理得到驗證,這裡就不再進行舉例了。
vector疊代器失效問題總結
(1)當執行erase方法時,指向删除節點的疊代器全部失效,指向删除節點之後的全部疊代器也失效
(2)當進行push_back()方法時,end操作傳回的疊代器肯定失效。
(3)當插入(push_back)一個元素後,capacity傳回值與沒有插入元素之前相比有改變,則需要重新加載整個容器,此時first和end操作傳回的疊代器都會失效。
(4)當插入(push_back)一個元素後,如果空間未重新配置設定,指向插入位置之前的元素的疊代器仍然有效,但指向插入位置之後元素的疊代器全部失效。
deque疊代器失效總結:
(1)對于deque,插入到除首尾位置之外的任何位置都會導緻疊代器、指針和引用都會失效,但是如果在首尾位置添加元素,疊代器會失效,但是指針和引用不會失效
(2)如果在首尾之外的任何位置删除元素,那麼指向被删除元素外其他元素的疊代器全部失效
(3)在其首部或尾部删除元素則隻會使指向被删除元素的疊代器失效。
對于關聯容器(如map, set,multimap,multiset),删除目前的iterator,僅僅會使目前的iterator失效,隻要在erase時,遞增目前iterator即可。這是因為map之類的容器,使用了紅黑樹來實作,插入、删除一個結點不會對其他結點造成影響。erase疊代器隻是被删元素的疊代器失效,但是傳回值為void,是以要采用erase(iter++)的方式删除疊代器。
首先來看一下map疊代器失效的一個例子:
運作結果:
這裡顯示疊代器失效,不能進行++ 操作,隻要稍作修改就可以了:
此時就可以成功删除key值為5的元素了,而且疊代器++也沒有問題了。
這裡主要解釋一下erase(it++)的執行過程:這句話分三步走,先把iter傳值到erase裡面,然後iter自增,然後執行erase,是以iter在失效前已經自增了。
map是關聯容器,以紅黑樹或者平衡二叉樹組織資料,雖然删除了一個元素,整棵樹也會調整,以符合紅黑樹或者二叉樹的規範,但是單個節點在記憶體中的位址沒有變化,變化的是各節點之間的指向關系。
111