直接用 for 循环 + ++it 删除会崩溃:正向迭代中 erase() 后继续 ++it 导致使用失效迭代器;正确做法是 it = vec.erase(it) 接住返回值,或改用 erase-remove 惯用法。

直接用 for 循环 + ++it 删除会崩溃
这是最常踩的坑:在正向迭代中调用 erase() 后还继续 ++it,导致使用已失效的迭代器。例如:
for (auto it = vec.begin(); it != vec.end(); ++it) {
if (*it == 5) vec.erase(it); // ❌ it 失效,++it 是未定义行为
}
崩溃表现因编译器和模式而异:Debug 下可能抛 std::out_of_range 或断言失败;Release 下可能静默越界、跳过元素,甚至破坏后续内存。
erase() 返回值必须接住,不能丢
vec.erase(it) 不只是删元素,它返回一个**有效迭代器**,指向被删元素之后的下一个元素(若删的是最后一个,则返回 vec.end())。不接住这个返回值,就等于继续用野指针。
- 正确写法是把
it = vec.erase(it)作为删除分支的唯一操作 - 不删除时才手动
++it - 循环条件保持
it != vec.end(),但不要在 for 的第三部分写++it
典型安全结构:
for (auto it = vec.begin(); it != vec.end(); ) {
if (*it == 5) {
it = vec.erase(it); // ✅ 接住返回值,it 已更新
} else {
++it; // ✅ 只有不删时才前进
}
}
按条件批量删,优先用 remove_if + erase
如果目标是“删掉所有偶数”或“删掉满足某个 predicate 的元素”,别手写循环——用 erase-remove 惯用法。它只遍历一次、移动最少、无迭代器失效风险,且语义清晰。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
std::remove_if不真正删除,只是把保留元素前移,返回新逻辑尾部的迭代器 -
vec.erase()接收该迭代器和vec.end(),完成物理截断 - 时间复杂度稳定 O(n),比多次
erase的 O(n²) 高效得多
示例(删所有负数):
vec.erase(
std::remove_if(vec.begin(), vec.end(), [](int x) { return x <h3>用下标循环?必须倒着来</h3><p>如果非要用 <code>size_t i</code> 下标(比如逻辑依赖索引值),正向遍历删除会导致后续元素前移、下标错位,极大概率漏删或越界。唯一安全方式是倒序:</p>
- 从
i = vec.size() - 1开始,递减到0 - 每次
vec.erase(vec.begin() + i)后,前面未处理的元素索引不变 - 注意:
size()返回size_t,i >= 0在无符号类型下永远为真,必须写成i != static_cast<size_t>(-1)</size_t>或更稳妥地用ssize_t(C++20 起)或直接用int索引
简单可靠写法(假设元素数量不会超 int 范围):
for (int i = vec.size() - 1; i >= 0; --i) {
if (vec[i] == 0) vec.erase(vec.begin() + i);
}
最容易被忽略的一点:无论用哪种方式,只要涉及 erase(),都要确认迭代器或下标在调用前有效——vec.begin() + i 越界、it 已经是 vec.end()、或者容器为空时对 vec.begin() 做算术运算,都会触发未定义行为。边界检查不是可选项,是必做动作。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










