vector::erase删除单个元素后原迭代器失效,须用其返回值更新;正确写法为it = vec.erase(it),或用remove-erase惯用法。

vector::erase 删除单个元素时,迭代器必须重新赋值
调用 vec.erase(it) 后,被删元素及其之后所有元素的内存位置前移,it 所指位置已无效——它变成悬垂迭代器,继续 ++ 或解引用会触发未定义行为(常见表现:程序崩溃、随机值、Debug 断言失败)。
正确做法是利用 erase() 的返回值:它返回指向**被删元素后一个元素**的有效迭代器。所以循环删除时不能写 it++,而要写 it = vec.erase(it)。
- 错误写法:
for (auto it = vec.begin(); it != vec.end(); ++it) { if (*it == x) vec.erase(it); }→ 迭代器失效后仍 ++ - 正确写法:
for (auto it = vec.begin(); it != vec.end(); ) { if (*it == x) it = vec.erase(it); else ++it; } - 更简洁写法(C++11 起):
vec.erase(std::remove(vec.begin(), vec.end(), x), vec.end());—— 用「删除-移除惯用法」避免手动管理迭代器
用 erase 删除多个连续元素,区间右边界必须合法
vec.erase(first, last) 删除的是 [first, last) 左闭右开区间,last 本身不删,但必须满足 first 。越界传入 vec.end() + 1 或 vec.begin() - 1 会导致未定义行为。
- 安全删除末尾 3 个元素:
vec.erase(vec.end() - std::min(3UL, vec.size()), vec.end());(先防 size() - 误用示例:
vec.erase(vec.begin() + 10, vec.begin() + 5)→ 区间反向,行为未定义 - 注意
size()返回size_t,与有符号 int 混算可能引发极大正数(如vec.size() - 10在空 vector 下变成 18446744073709551606)
erase 后 capacity 不变,但 size 减小
erase 只改变逻辑长度(size()),底层分配的内存(capacity())不受影响。这意味着反复增删可能导致内存浪费,但不会触发额外内存重分配。
立即学习“C++免费学习笔记(深入)”;
- 想真正释放多余内存:删完后调用
vec.shrink_to_fit();(C++11 起,非强制,只是请求) - 若需确保释放,可交换空 vector:
std::vector(vec).swap(vec); - 注意
shrink_to_fit()是异步操作,不保证立即生效;某些 STL 实现(如 libstdc++)可能忽略该请求
在 range-based for 循环里不能调用 erase
range-based for 底层依赖 begin()/end(),且隐式持有迭代器。一旦在循环体内调用 erase,容器结构变化导致所有现存迭代器失效,包括循环内部维护的那个——直接导致编译通过但运行时崩溃或静默错误。
- 绝对禁止:
for (auto& x : vec) { if (x == 0) vec.erase(/*...*/); } - 替代方案:用传统 for + 索引(注意索引随 size 变化),或改用
std::remove惯用法,或用 while + 迭代器(带 erase 返回值) - 哪怕只删一个元素,也破坏了 range-for 的前提假设,没有例外
实际项目里最常踩的坑不是不会写 erase,而是忘了它让“当前迭代器立刻作废”这个事实——尤其在嵌套条件、提前 return 或异常路径中,容易漏掉对迭代器状态的检查。别依赖调试器显示的“看起来还正常”,未定义行为在 Release 下才真正露馅。










