迭代器失效(Iterator Invalidation)
在 C++ 中,迭代器失效(Iterator Invalidation)指的是 迭代器在容器发生修改后变得无效,访问它会导致未定义行为(UB)。迭代器失效通常发生在 删除(erase)、插入(insert)、扩容(resize)、清空(clear) 等操作后。
1. 迭代器失效的常见情况
(1)删除元素(erase() 导致迭代器失效)
- 在
vector、deque、list等容器中,删除元素可能会使当前迭代器或后续迭代器失效。
✅ 解决方法
- 对于
vector和deque,删除元素后,必须更新迭代器。 - 对于
list和unordered_map,erase()仅使当前迭代器失效,后续迭代器仍然有效。
示例:vector 的 erase()
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
auto it = v.begin() + 2; // 指向 v[2] (3)
v.erase(it); // 删除 v[2] (3),导致迭代器失效
std::cout << *it; // ❌ 未定义行为(UB),it 失效
}
✅ 解决方法
auto it = v.erase(it); // `erase()` 返回删除元素的下一个迭代器
std::cout << *it; // ✅ 安全
(2)插入元素(insert() 可能导致扩容)
- 对于
vector和deque,如果insert()触发 扩容(reallocation),则所有迭代器都会失效。 list和map的insert()不会使已有迭代器失效。
示例:vector 的 insert()
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3};
auto it = v.begin(); // 指向 v[0]
v.insert(v.begin(), 0); // 在开头插入元素
std::cout << *it; // ❌ UB,迭代器失效
}
✅ 解决方法
auto new_it = v.insert(v.begin(), 0); // 重新获取有效迭代器
std::cout << *new_it; // ✅ 安全
(3)容器扩容(push_back()、resize() 导致迭代器失效)
vector可能扩容(reallocate)导致所有迭代器失效。list和map由于动态分配内存,不受影响。
示例:vector 的 push_back()
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3};
auto it = v.begin(); // 指向 v[0]
v.push_back(4); // 可能触发扩容,所有迭代器失效
std::cout << *it; // ❌ UB,it 失效
}
✅ 解决方法
v.reserve(10); // 预分配足够空间,避免扩容
(4)清空容器(clear() 导致所有迭代器失效)
clear()会删除所有元素,因此所有迭代器都失效。
std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.clear(); // 清空容器,所有迭代器失效
std::cout << *it; // ❌ UB
✅ clear() 后需要重新获取迭代器!
(5)deque 特殊情况
deque的erase()会导致所有后续迭代器失效,但不会影响前面的迭代器。push_front()或push_back()可能导致所有迭代器失效。
示例
#include <deque>
#include <iostream>
int main() {
std::deque<int> dq = {1, 2, 3, 4, 5};
auto it = dq.begin() + 2; // 指向 dq[2]
dq.erase(it); // 删除 dq[2],后续迭代器失效
}
✅ list 不会出现此问题,因为它是双向链表,erase() 只影响当前迭代器。
2. 容器迭代器失效规则
| 容器 | 插入元素 | 删除元素 | 扩容(resize() / push_back()) | 清空(clear()) |
|---|---|---|---|---|
vector | 可能导致扩容,所有迭代器失效 | 失效 & 需要更新迭代器 | 可能扩容,所有迭代器失效 | 失效 |
deque | push_front() / push_back() 可能导致所有迭代器失效 | 删除后续迭代器失效 | 可能扩容,所有迭代器失效 | 失效 |
list | 不影响迭代器 | 仅当前迭代器失效 | 不会扩容,安全 | 失效 |
map/set | 不影响迭代器 | 仅当前迭代器失效 | 不会扩容,安全 | 失效 |
✅ 避免 vector、deque 的迭代器失效,list、map 更安全!
3. 解决迭代器失效的方法
(1)更新迭代器
auto it = v.erase(it); // `erase()` 返回删除元素的下一个迭代器
(2)使用索引而非迭代器
for (size_t i = 0; i < v.size(); ++i) { // 避免迭代器失效
if (v[i] == 3) {
v.erase(v.begin() + i);
}
}
(3)使用 remove_if() + erase()
v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x == 3; }), v.end());
✅ 更安全的方式,避免手动管理迭代器!
4. 结论
- 删除元素(
erase()):对vector和deque,必须更新迭代器,list影响最小。 - 插入元素(
insert()):vector可能导致扩容,所有迭代器失效。 - 容器扩容(
push_back()):vector和deque可能触发所有迭代器失效。 - 清空容器(
clear()):所有迭代器失效。
✅ vector 和 deque 迭代器失效风险高,list 和 map 更稳定!
✅ 使用 erase() 返回值、索引遍历、remove_if() 等方式避免迭代器失效!
🚀 牢记迭代器失效规则,写出更安全的 C++ 代码!
2983

被折叠的 条评论
为什么被折叠?



