C++迭代器失效的避坑指南
1. 什么是迭代器失效?
在 C++ 中,迭代器(iterator) 是一種類似指針的對象,用于遍歷 STL 容器(如 vector、list、map 等)。
迭代器失效是指在對容器進(jìn)行某些操作(如插入、刪除)后,原本有效的迭代器變得不可用,繼續(xù)使用它會導(dǎo)致 未定義行為(Undefined Behavior, UB),如程序崩潰、數(shù)據(jù)錯(cuò)誤等
2. 哪些操作會導(dǎo)致迭代器失效?
不同的容器有不同的迭代器失效規(guī)則,本文主要討論 vector
的迭代器失效問題。
2.1 vector 的插入操作(push_back, insert)
當(dāng)向 vector
插入元素時(shí):
- 如果
size() == capacity()
(容量已滿):vector
會重新分配更大的內(nèi)存,并拷貝原有數(shù)據(jù)。- 所有迭代器失效(包括
begin()
,end()
等)。
- 如果
size() < capacity()
(容量未滿):- 插入點(diǎn)之前的迭代器仍然有效。
- 插入點(diǎn)及之后的迭代器失效(因?yàn)樵乜赡鼙灰苿?dòng))。
示例:push_back 導(dǎo)致迭代器失效
vector<int> v = {1, 2, 3}; auto it = v.begin(); // it 指向 1 v.push_back(4); // 可能觸發(fā)重新分配內(nèi)存 cout << *it; // ? 危險(xiǎn)!it 可能失效
如何避免?
- 提前預(yù)留空間(
reserve()
):
vector<int> v; v.reserve(100); // 預(yù)留 100 個(gè)元素的空間 auto it = v.begin(); v.push_back(1); // 不會重新分配,it 仍然有效
- 使用索引代替迭代器(如果允許)。
2.2 vector 的刪除操作(erase, pop_back)
當(dāng)從 vector
刪除元素時(shí):
- 被刪除元素的迭代器失效。
- 被刪除元素之后的所有迭代器失效(因?yàn)楹竺娴脑貢蚯耙苿?dòng))。
- 刪除點(diǎn)之前的迭代器仍然有效。
示例:erase 導(dǎo)致迭代器失效
vector<int> v = {1, 2, 3, 4}; auto it = v.begin() + 2; // it 指向 3 v.erase(v.begin() + 1); // 刪除 2 cout << *it; // ? 危險(xiǎn)!it 已經(jīng)失效(3 已經(jīng)前移)
如何正確刪除?
- 使用
erase
的返回值(返回下一個(gè)有效迭代器):
vector<int> v = {1, 2, 3, 4}; auto it = v.begin(); while (it != v.end()) { if (*it % 2 == 0) { it = v.erase(it); // 刪除并更新 it } else { it++; // 否則正常遞增 } }
反向遍歷(避免迭代器失效)
for (auto it = v.rbegin(); it != v.rend(); ) { if (*it % 2 == 0) { it = vector<int>::reverse_iterator(v.erase(it.base() - 1)); } else { it++; } }
3. 其他容器的迭代器失效情況
容器 | 插入操作(insert) | 刪除操作(erase) |
---|---|---|
vector | 可能失效(取決于容量) | 被刪除及后面的失效 |
deque | 可能失效(首尾安全) | 被刪除及附近的失效 |
list | 不會失效 | 僅被刪除的失效 |
map /set | 不會失效 | 僅被刪除的失效 |
4. 總結(jié)
vector
插入時(shí):- 可能失效(如果觸發(fā)重新分配)。
- 避免方法:提前
reserve()
或使用索引。
vector
刪除時(shí):- 被刪除及后面的迭代器失效。
- 正確做法:使用
erase
返回值或反向遍歷。
- 其他容器(如
list
、map
)通常更安全,但仍需謹(jǐn)慎。
最佳實(shí)踐:
- 避免在遍歷時(shí)直接修改容器,除非明確知道迭代器是否有效。
- 盡量使用
range-based for
或算法(如remove_if
),減少手動(dòng)管理迭代器。 - 調(diào)試時(shí)使用
-D_GLIBCXX_DEBUG
(GCC)檢測迭代器錯(cuò)誤。
以上就是C++迭代器失效的避坑指南的詳細(xì)內(nèi)容,更多關(guān)于C++迭代器失效的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法
本篇文章是對數(shù)組中求第K大數(shù)的實(shí)現(xiàn)方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05C++實(shí)現(xiàn)LeetCode(30.串聯(lián)所有單詞的子串)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(30.串聯(lián)所有單詞的子串),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng)
這篇文章主要介紹了C語言實(shí)現(xiàn)游戲VIP停車場管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12詳解C++?OpenCV實(shí)現(xiàn)圖像拼接的原理及方法
本文以實(shí)現(xiàn)圖像拼接為目標(biāo),把分割開的圖像進(jìn)行拼接還原,核心的內(nèi)容包括:OpenCV圖像拼接相關(guān)原理以及OpenCV圖像拼接案例的實(shí)現(xiàn),感興趣的可以了解一下2022-07-07C++通過控制臺訪問deepseek接口并進(jìn)行對話
這篇文章主要為大家詳細(xì)介紹了C++如何通過控制臺訪問deepseek接口并進(jìn)行對話,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-02-02C語言數(shù)組實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語言數(shù)組實(shí)現(xiàn)學(xué)生信息管理系統(tǒng)設(shè)計(jì),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01C++?IO設(shè)備讀寫功能實(shí)現(xiàn)詳解
C++的文件IO(Input,Output)操作就是指對文件進(jìn)行讀寫(輸入與輸出)的操作。輸入就是從磁盤上的文件中讀取內(nèi)容到內(nèi)存中。輸出就是將內(nèi)存中的數(shù)據(jù)內(nèi)容輸出或者說寫入到磁盤的文件中,這篇文章主要介紹了C++?IO設(shè)備讀寫功能實(shí)現(xiàn)2022-11-11