在stl容器中,經常會出現迭代器失效導致程式執行時崩潰,那迭代器究竟是如何失效的呢?
迭代器(iterator)是乙個可以對其執行類似指標的操作(如:解除引用(operator*())和遞增(operator++()))的物件,我們可以將它理解成為乙個指標。但它又不是我們所謂普通的指標,我們可以稱之為廣義指標,你可以通過sizeof(vector::iterator)來檢視,所佔記憶體並不是4個位元組。
向容器中新增元素和從容器中刪除元素的操作可能會使指向容器元素的指標、引用或者迭代器失效。
乙個失效的指標引用或者迭代器將不再表示任何元素。如果我們使用失效的指標、引用或者迭代器會造成很嚴重的程式錯誤,很容易會導致程式執行時崩潰。
首先對於vector而言,新增和刪除操作可能使容器的部分或者全部迭代器失效。那為什麼迭代器會失效呢?vector元素在記憶體中是順序儲存,試想:如果當前容器中已經存在了10個元素,現在又要新增乙個元素到容器中,但是記憶體中緊跟在這10個元素後面沒有乙個空閒空間,而vector的元素必須順序儲存一邊索引訪問,所以我們不能在記憶體中隨便找個地方儲存這個元素。於是vector必須重新分配儲存空間,用來存放原來的元素以及新新增的元素:存放在舊儲存空間的元素被複製到新的儲存空間裡,接著插入新的元素,最後撤銷舊的儲存空間。這種情況發生,一定會導致vector容器的所有迭代器都失效。
我們看到實現上述所說的分配和撤銷記憶體空間的方式以實現vector的自增長性,效率是極其低下的。為了使vector容器實現快速的記憶體分配,實際分配的容器會比當前所需的空間多一些,vector容器預留了這些額外的儲存區,用來存放新新增的元素,而不需要每次都重新分配新的儲存空間。你可以從vector裡實現capacity和reserve成員可以看出這種機制。
capacity和size的區別:size是容器當前擁有的元素個數,而capacity則指容器在必須分配新儲存空間之前可以儲存的元素總數。
vector和string迭代器的幾種失效的情況:
(a)如果儲存空間被重新分配,則指向容器的迭代器都會失效。(當新插入元素的數目 count + size() 大於 capacity() 時儲存空間被重新分配)
(b)如果儲存空間未被重新分配,則插入位置之前的元素的迭代器有效,但指向插入位置之後的迭代器全部失效。
deque迭代器的失效情況:
1.插入元素在任何位置都會是迭代器失效,但如果在首位置插入元素,指向存在元素的指標和引用不會失效。
2.在deque容器的任何其他位置的插入和刪除操作將使指向該容器元素的所有迭代器失效。
list和forw_list迭代器的失效情況:
(a)新增元素會使指向容器的迭代器都會失效。
(b)刪除元素是會導致刪除位置和後面的迭代器失效。
對於關聯容器map, set, multimap,multiset
刪除當前的iterator,僅僅會使當前的iterator失效,只要在erase時,遞增當前iterator即可。這是因為map之類的容器,使用了紅黑樹來實現,插入、刪除乙個結點不會對其他結點造成影響。
總結一下迭代器失效的根本原因:
1.由於容器元素整體「遷移」導致存放原容器元素的空間不再有效,從而使得指向原空間的迭代器失效。
2.由於刪除元素使得某些元素次序發生變化使得原本指向某元素的迭代器不再指向希望指向的元素。
3.對於關聯式容器(map, list, set)元素的刪除,插入操作會導致指向該元素的迭代器失效,其他元素迭代器不受影響。
4.對於順序式容器(vector)元素的刪除、插入操作會導致指向該元素以及後面的元素的迭代器失效。
如何避免迭代器失效:
1. 當我們使用迭代器時,最小化要求迭代器必須保持有效的程式片段是乙個避免迭代器失效很好的方法。
2. 由於向迭代器新增和刪除元素的程式很可能會使當前的迭代器失效,因此當我們每次發生改變容器的任何操作時,尤其是對vector、string、deque 這些容器,最好能重新定位迭代器,防止迭代器失效。
3.當我們刪除容器元素時,erase()會返回下乙個元素的迭代器位置,在程式中我們可以抓住這一點,正確地刪除容器元素。(原始碼如下)
vector
::iterator it = v.begin();
for (; it != v.end();)
迭代器失效 典型的迭代器失效
首先對於vector而言,新增和刪除操作可能使容器的部分或者全部迭代器失效。那為什麼迭代器會失效呢?vector元素在記憶體中是順序儲存,試想 如果當前容器中已經存在了10個元素,現在又要新增乙個元素到容器中,但是記憶體中緊跟在這10個元素後面沒有乙個空閒空間,而vector的元素必須順序儲存一邊索...
迭代器失效
迭代器 iterator 是乙個可以對其執行類似指標的操作 如 解除引用 operator 和遞增 operator 的物件,我們可以將它理解成為乙個指標。但它又不是我們所謂普通的指標,我們可以稱之為廣義指標,你可以通過sizeof vector iterator 來檢視,所佔記憶體並不是4個位元組...
迭代器失效
對於序列式容器 如vector,deque 刪除當前的iterator會使後面所有元素的iterator都失效。這是因為vetor,deque使用了連續分配的記憶體,刪除乙個元素導致後面所有的元素會向前移動乙個位置。所以不能使用erase iter 的方式,還好erase方法可以返回下乙個有效的it...