erase后迭代器必然失效,正确做法是用其返回值续接(如it = v.erase(it))或采用remove-erase惯用法;反向遍历或调整索引也可避免失效问题。
调用 vector::erase 删除元素后,被删位置及之后所有迭代器全部失效。常见错误是写成:for (auto it = v.begin(); it != v.end(); ++it) { if (...) v.erase(it); }——这会导致 it 失效后又被 ++it 解引用,触发未定义行为(UB),多数情况直接崩溃或静默错乱。
根本原因是 vector 内部是连续内存,删除中间元素会引发后续元素前移,原 it 指向的地址已不属于该容器,更别说自增操作了。
vector::erase 返回**删除位置之后的第一个有效迭代器**(C++11起),正好可用来跳过已处理位置,避免失效问题。
it = v.erase(it); —— 此时 it 已指向下一个有效位置,不要再 ++it
while 遍历删除多个元素:auto it = v.begin(); while (it != v.end()) { if (condition) it = v.erase(it); else ++it; }
for 循环,必须把 ++it 放在 else 分支里,或统一用 it = v.erase(it) 后不自增当要按值或谓词批量删除时,std::remove + erase 组合更高效、更简洁,且完全规避迭代器管理问题:
v.erase(std::remove(v.begin(), v.end(), 42), v.end()); // 删除所有值为42的元素
v.erase(std::remove_if(v.begin(), v.end(), [](int x) { return x < 0; }), v.end()); // 删除所有负数
原理:std::remove 不真正删

erase 再一次性擦除尾部冗余区间。整个过程只遍历一次,无迭代器失效风险。
⚠️ 注意:remove 是算法,不适用于 list 或 deque 的“高效删除”场景(它们有成员函数 remove),但对 vector 来说,这是最稳的选择。
如果只是简单判断删除,且不需要访问前后元素,用下标反而更直观、不易出错:
for (int i = v.size() - 1; i >= 0; --i) { // 从后往前删,避免下标偏移
if (v[i] % 2 == 0) v.erase(v.begin() + i);
}
或者正向遍历时动态调整上界:for (int i = 0; i —— 这和迭代器版的 while 逻辑一致,只是换种写法。
索引方式在小数据量、逻辑简单时可读性高;但要注意 v.size() 是 O(1),频繁调用无性能压力,别担心。
真正容易忽略的是:即使只删一个元素,只要用了 erase,它后面所有迭代器就全废了——包括你刚存下来的 end()。所以别缓存 v.end() 在循环条件里,也别在 erase 后还拿旧 it 做比较或解引用。