【C++】迭代器失效问题
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
一、什么是迭代器失效?
二、哪些操作会导致迭代器失效?
1. vector的迭代器失效
三、迭代器失效的严重后果
四、如何避免迭代器失效?
1. 正确使用erase
2. 插入元素时注意
3. 使用算法替代手动循环
五、各容器迭代器失效总结表
一、什么是迭代器失效?
在C++中,迭代器(iterator)就像STL容器的"智能指针",为我们提供了遍历容器元素的统一方式。但是,当容器结构发生变化时,原本有效的迭代器可能会变得无效,这种现象就称为"迭代器失效"。
二、哪些操作会导致迭代器失效?
1. vector的迭代器失效
vector作为动态数组,在内存中是连续存储的,因此任何可能引起内存重新分配的操作都会使所有迭代器失效:
std::vector<int> v = {1, 2, 3, 4};
auto it = v.begin() + 2; // 指向3v.push_back(5); // 可能导致内存重新分配
// 此时it可能失效!
具体会导致vector迭代器失效的操作:
-
push_back()
(当容量不足时) -
insert()
-
reserve()
-
resize()
-
erase()
(被删除元素及其后的迭代器都失效)
三、迭代器失效的严重后果
使用失效的迭代器会导致未定义行为(UB),可能表现为:
-
程序崩溃
-
数据损坏
-
看似正常工作但结果错误
-
更糟的是可能在发布版本中才出现问题
std::vector<int> v = {1, 2, 3, 4};
for(auto it = v.begin(); it != v.end(); ) {if(*it % 2 == 0) {v.erase(it); // 错误!erase后it失效// 应该改为 it = v.erase(it);} else {++it;}
}
四、如何避免迭代器失效?
1. 正确使用erase
对于序列容器(vector, deque, list):
it = container.erase(it); // erase返回下一个有效迭代器
对于关联容器(map, set):
container.erase(it++); // 先传递it副本,再递增
2. 插入元素时注意
std::vector<int> v = {1, 2, 3}; auto it = v.begin() + 1; v.insert(it, 4); // it可能失效 // 应该重新获取迭代器 it = v.begin() + 2;
3. 使用算法替代手动循环
std::vector<int> v = {1, 2, 3, 4}; // 删除所有偶数 v.erase(std::remove_if(v.begin(), v.end(), [](int n){return n%2==0;}), v.end());
五、各容器迭代器失效总结表
容器类型 | 导致迭代器失效的操作 |
---|---|
vector | 插入(导致扩容)、删除(被删元素及之后) |
deque | 首尾插入(仅影响插入点)、中间插入(全部失效)、删除(被删元素及之后) |
list | 仅被删除元素的迭代器失效 |
map/set | 仅被删除元素的迭代器失效 |
unordered_map/set | 插入(导致rehash)、删除(被删元素) |