标准做法是erase-remove惯用法:先用std::remove将不匹配元素前移并返回新逻辑尾迭代器,再用vector::erase删除该位置到end()的冗余部分;顺序不可颠倒,否则无法正确删除所有匹配元素。

用 erase + remove 组合是标准做法
直接调用 vector::erase 无法安全删除所有匹配元素,因为迭代器会失效。必须配合 std::remove(或 std::remove_if)做“逻辑移除”,再用 erase 物理擦除尾部垃圾。
这是 C++ 中删除指定值的惯用法(Erase-Remove Idiom),不是偷懒,而是为避免越界和迭代器失效。
-
std::remove不真正删元素,只是把不匹配的值往前挪,返回新逻辑结尾的迭代器 -
erase接收两个迭代器,删掉从该位置到end()的所有内容 - 顺序不能反:必须先
remove,再erase,否则删的是错的区间
std::vector<int> v = {1, 2, 3, 2, 4, 2};
v.erase(std::remove(v.begin(), v.end(), 2), v.end()); // 删除所有 2
// v 变成 {1, 3, 4}
</int>
要删第一个匹配元素?用 std::find + erase
如果只删一个(比如删首次出现的 5),std::remove 太重,直接找位置再删更清晰、高效。
-
std::find返回第一个匹配项的迭代器,没找到时等于v.end() - 必须检查是否找到,否则对
v.end()调用erase是未定义行为 - 单次删除后,后续元素自动前移,其他迭代器/索引可能失效
auto it = std::find(v.begin(), v.end(), 5);
if (it != v.end()) {
v.erase(it); // 只删第一个 5
}
按条件删除(比如删所有偶数)?用 remove_if
当判断逻辑复杂(不只是相等),就得用 std::remove_if,传入 lambda 或函数对象。
- lambda 捕获需谨慎:不要在谓词里修改容器本身,否则迭代器行为不可控
- 注意
remove_if对每个元素调用谓词一次,无序遍历,不保证执行顺序 - 性能上,和
remove一样是 O(n),但谓词开销另算
// 删所有偶数
v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x % 2 == 0; }), v.end());
为什么不能用 for 循环边遍历边 erase?
常见错误写法:for (auto it = v.begin(); it != v.end(); ++it) 里遇到目标就 v.erase(it) —— 这会导致 it 立即失效,下一次 ++it 出问题。
-
erase返回下一个有效迭代器,但多数人忘了接住它 - 若用索引
for (int i=0; i,删元素后 v.size()变小,但i还自增,会跳过下一个元素 - 即使加
i--补救,逻辑也易错,可读性差,且无法处理多个连续匹配
真正需要手动控制循环的场景极少,优先走 remove 系列;非要用循环,至少写成 it = v.erase(it) 并跳过 ++it。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











