题目
编写程序,演示在遍历 std::vector 容器的过程中删除所有偶数元素时最容易踩入的“迭代器失效”(Iterator Invalidation)死循环/越界崩溃陷阱;分别给出基于 it = vec.erase(it) 返回值步进的安全传统修正方案,以及现代 C++ 标准推荐的 std::remove_if 与 C++20 统一 std::erase_if 的彻底删除写法。
输入格式:无需外部输入。
输出格式:输出删除偶数前后容器内元素序列与正确迭代过程。
数据范围与约定:STL 迭代器生命周期与安全修改。
思路与算法
1. 迭代器失效的成因
对 std::vector 执行 erase(it) 会导致被删元素之后的所有元素向前平移拷贝一位。此时原本的迭代器 it 已经失效;若循环中仍然无脑执行 ++it,不仅会漏检紧随其后的下一个元素,更可能越过 vec.end() 触发段错误(Segmentation fault)。
2. erase 返回值步进模式
标准规定 vec.erase(it) 会返回指向“被删除元素之后那个新元素”的合法迭代器。因此正确写法是在删除时不执行 ++it,仅在不删除时才 ++it。
3. 现代 Erase-Remove 惯用法
手写循环删除的时间复杂度为 O(K * N);而使用标准算法 vec.erase(std::remove_if(...), vec.end()) 为线性 O(N),无额外冗余移动。
完整程序
#include <iostream>
#include <vector>
#include <algorithm>
int main() {
// 1. 传统迭代器循环安全删除(删除所有偶数)
std::vector<int> vec1 = {1, 2, 2, 3, 4, 5, 6, 6, 7};
std::cout << "--- 1. 正确的 it = vec.erase(it) 迭代模式 ---\n";
std::cout << "原数组: ";
for (int x : vec1) std::cout << x << " ";
std::cout << "\n";
for (auto it = vec1.begin(); it != vec1.end(); /* 内部步进 */) {
if (*it % 2 == 0) {
// erase 返回被删除元素后面的有效迭代器
it = vec1.erase(it);
} else {
++it; // 只有不删除时才向后步进
}
}
std::cout << "删除所有偶数后: ";
for (int x : vec1) std::cout << x << " ";
std::cout << "\n\n";
// 2. 现代 C++ 规范:Erase-Remove Idiom
std::vector<int> vec2 = {10, 15, 20, 25, 30, 35};
std::cout << "--- 2. 高效算法 erase + remove_if ---\n";
vec2.erase(
std::remove_if(vec2.begin(), vec2.end(), [](int n) { return n % 2 == 0; }),
vec2.end()
);
std::cout << "Erase-Remove 删除后: ";
for (int x : vec2) std::cout << x << " ";
std::cout << "\n";
return 0;
}运行示例
输出:
--- 1. 正确的 it = vec.erase(it) 迭代模式 ---
原数组: 1 2 2 3 4 5 6 6 7
删除所有偶数后: 1 3 5 7
--- 2. 高效算法 erase + remove_if ---
Erase-Remove 删除后: 15 25 35