c 迭代器失效問題探幽

2021-10-12 16:45:53 字數 2439 閱讀 4757

上週做專案時遇到乙個bug,最終定位是錯誤得使用了c++迭代器導致,錯誤**如下:

for (auto it = framecachemap.begin(); it != framecachemap.end(); it++) 

}

有效的迭代器或者指向某個元素,或者指向容器中尾元素的下一位置;其他所有情況都屬於無效。而使用失效的迭代器是一種嚴重的程式設計錯誤,很可能引起與使用未初始化指標一樣的問題(出自c++ primer)。

情況一:容器的儲存空間被重新分配

這裡以vector為例,vector的元素是連續儲存的,但相比陣列它的大小是可變的即會動態增長。具體來說就是vector有乙個capacity和乙個size,size是指它已經儲存的元素的數目,而capacity則是在不分配新的記憶體空間的前提下它最多可以儲存多少元素,當capacity不夠時會重新分配一段更大的儲存空間,至於vector動態增長策略,本帖不作細緻討論,可參考vector原始碼,vector空間的動態增長。

當vector的大小增大到capacity不夠時,內部會重新分配一段連續的儲存空間,原先的迭代器都會失效,所以使用push_back操作時盡量不要和迭代器沾邊。如下**就會導致執行錯誤:

std::vectorvi;

vi.push_back(1);

auto it = vi.begin();

vi.push_back(4); //錯誤!!!vector的capacity改變,儲存空間重新分配,迭代器it失效

std::cout << *it << std::endl;

我們習慣的使用的for迴圈裡,很容易出現這種錯誤(我刷題有時候都會這樣寫0.0),如下:

std::vectorvi;

vi.push_back(1);

for (auto it = vi.begin(); it != vi.end(); it++)

std::cout << *it << std::endl;

}

不過也有可能出現push_back操作並沒有改變vector的capacity,這種情況下沒有重新分配連續儲存空間,使用push_back不會導致迭代器失效,但是我不建議抱有這種心理,因為我們可能並不了解vector capacity動態增長的策略,即使知道,每次push_back時我們也並不關注它此時的capacity和size的關係。

情況二:erase操作導致迭代器失效

在c++ primer中提到,當我們從乙個容器中刪除元素後,指向被刪除元素的迭代器、指標和引用會失效。當刪除乙個元素

這個其實比較好理解,元素都沒了,迭代器肯定失效,我在**實踐中確實是這樣的,如下**就執行出錯:

for (int i = 0; i < 24; i++) 

for (auto it = vi.begin(); it != vi.end(); it++)

std::cout << *it << std::endl; //迭代器it在等於20時失效,*it或者it++都會報錯

}

下面給出一些正確寫法

vector刪除元素

for (int i = 0; i < 24; i++) 

for(auto it = vi.begin(); it != vi.end();)else

}

map刪除元素

std::mapmp;

mp[0] = "0";

mp[1] = "1";

mp[2] = "2";

for (auto it = mp.begin(); it != mp.end();) else

}

這是因為map之類的容器,使用了紅黑樹來實現,插入、刪除乙個結點不會對其他結點造成影響。erase迭代器只是被刪元素的迭代器失效,但是返回值為void,所以要採用erase(iter++)的方式刪除迭代器。

解析: mp.erase(it++);這句話分三步走,先把it傳值到erase裡面,然後it自增,然後執行erase,所以it在失效前已經自增了。

list刪除元素

std::listlst;

for (int i = 0; i < 24; i++)

for (auto it = lst.begin(); it != lst.end();) else

}

對於鍊錶式容器(如list),刪除當前的iterator,僅僅會使當前的iterator失效,這是因為list之類的容器,使用了鍊錶來實現,插入、刪除乙個結點不會對其他結點造成影響。因此採用和map一樣的方式刪除即可。同時erase也會返回指向下乙個元素的有效迭代器,也可以使用vector的刪除方式。

小結本帖主要討論了迭代器失效的兩種情況

C 迭代器 迭代器失效問題

問題描述 輸入乙個整數陣列,實現乙個函式來調整該陣列中數字的順序,使得所有的奇數字於陣列的前半部分,所有的偶數字於位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。這是劍指offer上的一道經典習題,我們首先可以想到的解決方案是 再建立乙個臨時陣列把偶數先存放起來,然後把臨時空間的...

C 迭代器失效問題

迭代器失效 1 對於在記憶體中連續分布的容器 vector queue deque 插入或者刪除會使插入或者刪除點的迭代器以及之後的迭代器失效。2。對於非連續儲存的容器 list,forword list,map 插入或刪除僅僅使插入或者刪除點迭代器失效。解決方法 1 對於連續記憶體容器或者非連續記...

C 迭代器失效問題

迭代器失效問題一般是指對於stl容器來說,呼叫erase某迭代器之後,就不能再使用這個iterator了。解決方法 1 erase iter 這樣可以繼續使用該iter 2 it erase iter 這是利用erase函式的返回值,一般的erase函式都會返回乙個刪除迭代器的後繼迭代器。如果是er...