正确删除vector元素应使用erase返回的迭代器、反向迭代器或erase-remove惯用法;直接++it后erase会导致迭代器失效,下标法需删后i--。

用 erase 配合返回的迭代器,别用 ++it 硬写
直接在 for (auto it = v.begin(); it != v.end(); ++it) 里调 v.erase(it) 会导致迭代器失效,++it 访问已释放内存,行为未定义——轻则跳过元素,重则崩溃。
正确做法是让 erase 告诉你下一个有效位置:it = v.erase(it)。它删除当前元素后,返回指向新“下一个”元素的迭代器,不用再 ++it。
for (auto it = v.begin(); it != v.end(); ) {
if (should_delete(*it)) {
it = v.erase(it); // 删除并获取下一位置
} else {
++it; // 仅当不删时才递增
}
}
用反向迭代器 rbegin/rend 避开前移干扰
正向遍历时删除会改变后续元素索引,而反向遍历(从尾到头)删除元素不影响前面还没访问的迭代器有效性,逻辑更直觉。
注意:反向迭代器的 base() 不等于对应正向位置,但只要全程用 reverse_iterator 操作,就不需转换。
-
v.erase((++it).base())是错的——别混用正反向 - 安全写法:统一用
vector<int>::reverse_iterator</int>,删完继续--it - 适用于“按值删”或“条件简单”的场景,代码可读性比 erase+返回值略高
批量删除选 std::remove_if + erase(erase–remove 惯用法)
这是最推荐的通用解法,尤其适合多条件、高性能要求场景。它把要删的元素“挪到末尾”,再一次性擦除,避免反复移动内存。
std::remove_if 不真删,只重排;erase 接收两个迭代器,删掉中间那段——两者配合才是完整语义。
v.erase(
std::remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }),
v.end()
);
- 不能只写
std::remove_if就以为删了——容器大小没变 - lambda 捕获或复杂谓词没问题,但注意引用捕获在 lambda 存活期外使用会出问题
- 对
vector效率高;对list则优先用remove_if成员函数
用下标 size_t i 遍历时,删完要 i--
下标访问看似简单,但删掉第 i 个后,原 i+1 变成新 i,若不回退就会跳过它。
常见错误是删完写 i++ 或啥也不做,结果漏判相邻元素。
- 必须在
if (should_delete(v[i])) { v.erase(v.begin() + i); --i; }后立刻--i - 循环条件仍用
i ,因为 <code>v.size()会动态变小 - 注意
size_t是无符号类型,--i在i==0时会绕回极大值,务必先判断是否非空
push_back 或其他修改操作,就又得重新评估迭代器有效性。C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











