迭代器失效后继续用 it++ 会崩溃,因插入、删除或内存重新分配导致原有迭代器悬空;如 vector 扩容使所有迭代器失效,map 删除当前节点使该迭代器立即失效,后续解引用或自增将引发未定义行为。

迭代器失效后继续用 it++ 会崩溃
容器在插入、删除或重新分配内存时,原有迭代器可能失效。比如 std::vector 在 push_back() 触发扩容时,所有现存迭代器都变成悬空指针;std::map 删除当前指向的节点后,该迭代器立即失效。继续对它做 ++、*it 或传给算法,行为未定义——多数情况是段错误或读到垃圾值。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 删元素时别盲目写
for (auto it = c.begin(); it != c.end(); ++it),应改用返回下一个有效迭代器的接口,如it = c.erase(it) -
std::vector插入前先reserve(),减少意外扩容;若必须边遍历边插,优先考虑std::list或std::deque - 调试时打开 libstdc++ 的 _GLIBCXX_DEBUG 模式(编译加
-D_GLIBCXX_DEBUG),能捕获大部分迭代器误用
用 auto 声明迭代器比手写类型更安全
手写迭代器类型容易出错:比如把 std::vector<int>::iterator</int> 写成 const_iterator,或在 const 容器里用了非 const 迭代器,编译直接报错;更隐蔽的是,不同标准库实现对 iterator 和 const_iterator 是否为同一类型有差异,影响可移植性。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 一律用
auto it = c.begin(),让编译器推导;需要 const 语义就用auto it = c.cbegin() - 函数参数中避免裸写
std::vector<t>::iterator</t>,改用模板参数或std::span+ 迭代器范围(C++20) - 注意
auto推导出的是值类型,不是引用——要修改元素得写auto& e : c或auto it = c.begin()后解引用赋值
end() 迭代器不能解引用,但可以比较和自增
c.end() 指向“最后一个元素之后的位置”,本身不指向任何合法元素。常见错误是写 *(c.end()) 或 for (auto it = c.begin(); it ,前者崩溃,后者越界一格。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 循环条件永远用
it != c.end(),不要用或 <code>==(虽多数实现==可用,但语义不对) -
std::next(it, n)比手动++n 次更安全,它内部会检查是否越过end() - 想取最后一个元素?别用
*(--c.end())(对空容器 UB),改用c.empty() ? throw : c.back()
不同容器的迭代器类别影响算法选择
std::vector 迭代器支持随机访问(it += 5、it[3]),std::list 只支持双向移动(++/--),std::forward_list 甚至不支持 --。传错迭代器给算法会导致编译失败或性能灾难——比如把 list::iterator 传给 std::sort()(要求随机访问)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 查文档看容器的
iterator_category:vector/map/set 是random_access_iterator_tag,list 是bidirectional_iterator_tag,forward_list 是forward_iterator_tag - 泛型代码中用
std::distance(a, b)替代b - a,前者适配所有迭代器类别 - 用
std::advance(it, n)移动迭代器,它会根据类别自动选++或跳转,避免手写循环
迭代器不是指针,但表现像指针;它也不是智能指针,不管理资源。最常被忽略的是:失效判断完全依赖容器文档,没有运行时检查机制——写的时候觉得没问题,换一个插入位置、换一个编译器版本,就挂了。











