迭代器失效指容器结构变化后原有迭代器指向无效位置,导致未定义行为。std::vector插入可能引发扩容,致所有迭代器失效;erase后返回有效迭代器。std::deque在首尾插入或删除均可能使所有迭代器失效。std::list和forward_list插入不失效,仅删除目标元素迭代器失效。关联容器如map、set插入通常不失效,删除仅影响对应迭代器;unordered系列在rehash时所有迭代器失效。避免方法包括:用erase返回值更新迭代器、避免保存长期使用的迭代器、使用erase-remove惯用法、vector预留空间reserve()。掌握各容器规则并遵循安全编码习惯可有效防止问题发生。

在C++中使用STL容器时,迭代器失效是一个常见但容易被忽视的问题。当对容器进行增删操作后,原有的迭代器可能不再有效,继续使用会导致未定义行为。理解不同容器在不同操作下的迭代器失效规则,是写出安全、稳定代码的关键。
什么是迭代器失效?
迭代器本质上是指向容器元素的“指针”。当容器内部结构发生变化(如内存重分配、元素移动或删除),原来的迭代器指向的位置可能已无效。此时若通过该迭代器访问或修改数据,程序会崩溃或产生不可预测的结果。
例如,在std::vector中插入元素可能导致扩容,原有内存被释放并重新分配,所有迭代器全部失效。
常见容器的迭代器失效情况
vector- 插入操作:如果插入导致容量不足而重新分配内存,所有迭代器、指针、引用全部失效;否则仅插入位置及之后的迭代器失效。
- 删除操作:erase 删除元素后,被删元素及其之后的所有迭代器失效。返回值是下一个有效迭代器。
- 在首尾插入不一定导致内存重分配,但一旦发生重分配,所有迭代器失效。
- 中间插入几乎总是导致失效。
- 删除任一元素,所有迭代器均失效(因deque结构复杂,节点可能被重组)。
- 插入操作不会导致任何迭代器失效(链表结构,新增节点不影响原有节点地址)。
- 删除操作仅使指向被删元素的迭代器失效,其他不受影响。
- 插入操作一般不使已有迭代器失效(尤其是关联容器基于红黑树)。
- 删除操作仅使指向被删元素的迭代器失效。
- unordered系列在 rehash 时会使所有迭代器失效(仅适用于插入触发扩容的情况)。
如何避免迭代器失效带来的陷阱?
掌握规则之外,编写代码时应采取防御性策略:
立即学习“C++免费学习笔记(深入)”;
- 使用 erase 返回值更新迭代器:尤其是在循环中删除元素时,不要直接使用 ++it。
示例:
for (auto it = vec.begin(); it != vec.end();) {
if (*it % 2 == 0) {
it = vec.erase(it); // 正确:用返回值更新
} else {
++it;
}
}
// 删除所有偶数
vec.erase(std::remove_if(vec.begin(), vec.end(),
[](int n){ return n % 2 == 0; }),
vec.end());
总结
不同容器对迭代器的“保护”程度不同:vector 和 deque最容易出现大面积失效,list 和关联容器则更安全。关键是在做增删操作后,明确哪些迭代器还能用。养成良好的编码习惯,善用标准库提供的机制,就能有效规避这类问题。
基本上就这些。写代码时多留意文档说明,特别是“iterators invalidated”这一节,能少走很多弯路。










