用erase配合迭代器删除元素,避免下标遍历;误删v.end()触发未定义行为;删首元素为O(n);多位置删除应先收集索引再倒序执行erase。

用 erase 配合迭代器,别用下标遍历删除
直接用 for (int i = 0; i 边遍历边调 <code>v.erase(v.begin() + i) 会导致跳过元素或越界——因为每次删除后,后面所有元素前移,但 i 还在自增。正确做法是让迭代器自己“接住” erase 返回的新位置。
-
erase删除单个元素时返回指向**被删元素后一个元素**的迭代器(C++11 起),不是void - 所以应写成:
it = v.erase(it),而不是v.erase(it); ++it - 若要条件删除多个,循环中不要无脑
++it,只在没删除时才递增
删除满足条件的所有元素:优先用 remove_if + erase 惯用法
这是最安全、最高效、也最不容易出错的方式,尤其适合按值或谓词批量删。它不改变未删除元素的相对顺序,且只遍历一次。
std::vector<int> v = {1, 2, 3, 2, 4, 2};
v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x == 2; }), v.end());
// 结果:{1, 3, 4}
-
remove_if不真正删除,只是把保留的元素往前挪,返回新逻辑尾部的迭代器 -
erase接收这个迭代器和v.end(),一次性抹掉“废弃段” - 避免了手动管理迭代器失效风险,也不依赖容器是否支持随机访问
删除最后一个元素用 pop_back,别用 erase
虽然 v.erase(v.end() - 1) 语法合法,但 pop_back() 更明确、更轻量,且不涉及迭代器算术(对某些 debug 模式下的 checked iterator 更友好)。
-
pop_back()是常数时间,无内存重分配(除非 capacity > size 太多,但那是另一回事) - 若误写成
v.erase(v.end()),会触发未定义行为——v.end()本身不可解引用,也不能传给erase作单元素删除 - 删除第一个元素用
v.erase(v.begin())没问题,但性能是 O(n),注意代价
在循环里删多个不同位置的元素?先收集索引再倒序删
如果必须根据复杂逻辑决定删哪些下标(比如按某种状态交叉判断),又不想用 remove_if,那就别边遍历边删。改用两阶段:先记下所有要删的 size_t 索引,再从大到小依次 erase(v.begin() + i)。
立即学习“C++免费学习笔记(深入)”;
- 倒序删是为了避免“前面删了,后面索引全偏移”导致删错位置
- 索引存
std::vector<size_t></size_t>或std::set<size_t></size_t>(自动排序),然后反向遍历 - 注意:用下标删本质仍是
erase(iterator),所以仍要确保索引 v.size(),且删完后v.size()变小
最容易被忽略的是:所有基于迭代器的删除操作,一旦发生 erase,**被删位置及之后的所有迭代器立即失效**(包括 end())。哪怕只是删一个元素,也不要假设其他保存的迭代器还能用。真要长期持有位置,考虑用下标,或改用 list / deque。vector 的优势在随机访问,不在频繁中间删除。


















