erase_if 是 c++20 引入的 非成员函数,用于安全高效删除容器中满足条件的元素,返回被删元素个数;需编译器支持 c++20 且包含 和对应容器头文件,不适用于子串删除或修改 map 键等未定义行为。

erase_if 在 C++20 中才可用,老标准直接用会编译失败
如果你的编译器报错 ‘erase_if’ was not declared in this scope,大概率是因为没开 C++20 或用了不支持的库版本。它不是 STL 容器成员函数,而是 <algorithm></algorithm> 里的非成员函数,且仅从 C++20 起标准化(GCC 10+、Clang 11+、MSVC 19.28+ 默认支持)。
实操建议:
- 确认编译选项:GCC/Clang 加
-std=c++20,MSVC 开启/std:c++20 - 头文件必须包含
<algorithm></algorithm>和对应容器头文件(如<vector></vector>) - 不要尝试在 C++17 项目里“手动实现同名函数”混用——标准 erase_if 对 vector/string 有特化优化,自己写的等效循环性能差、语义也不同
erase_if 删除 vector 元素时不会导致迭代器失效,但要注意返回值
和手写 remove_if + erase 两步不同,erase_if 是原子操作:内部调用容器的 erase 成员完成真实删除,所以你传进去的 lambda 拿到的始终是当前有效元素引用,不用担心遍历时跳过或越界。
但它不返回迭代器,而返回被删元素个数(size_t):
立即学习“C++免费学习笔记(深入)”;
std::vector<int> v = {1, 2, 3, 4, 5};
auto n = std::erase_if(v, [](int x) { return x % 2 == 0; }); // 删除偶数
// v 变成 {1, 3, 5},n == 2
常见错误现象:
- 误以为返回迭代器,接着做
++it—— 编译不过 - 对
std::list或std::forward_list用erase_if后,仍按旧习惯检查it != end()—— 实际已无迭代器参与,纯属多余
map/set 等关联容器不能直接用 erase_if 删除键值对
标准 erase_if 对 std::map、std::set 等只提供基于键的擦除重载(比如 erase_if(map, pred) 中 pred 参数类型是 const value_type&),但它**不支持修改 key 的谓词**,且底层仍走节点删除,性能尚可。
但要注意兼容性陷阱:
-
std::unordered_map在 libstdc++(GCC)中 C++20 下支持;但 MSVC 的早期 C++20 实现曾漏掉该重载,升级工具链前先测std::erase_if(my_map, [](const auto& p) { return p.second - 如果谓词里试图通过
p.first = ...修改 key —— 行为未定义,编译可能不报错,但运行时 map 可能损坏 - 想按 value 删除又兼顾性能?别硬套
erase_if,老实用循环 +erase(iterator)配合post-increment更稳:
for (auto it = m.begin(); it != m.end(); ) {
if (it->second < 0) it = m.erase(it);
else ++it;
}
string 也能用 erase_if,但注意它是按字符删,不是子串
std::string 是容器适配器,C++20 给它加了 erase_if 特化,参数是 char 或 unsigned char,不是 std::string 子串匹配。
使用场景很明确:清洗字符。比如去空格、去控制符、转小写后删元音……
std::string s = "Hello\tWorld\n";
std::erase_if(s, [](char c) { return std::isspace(static_cast<unsigned char>(c)); });
// s 变成 "HelloWorld"
容易踩的坑:
- 忘记
static_cast<unsigned char></unsigned>直接传char给std::isspace—— 若char是有符号且值为负(如 0xFF),行为未定义 - 想删掉所有 "ab" 子串却写
erase_if(s, [](char c) { return c == 'a' || c == 'b'; })—— 这只会删单个字符,不是子串逻辑 - 对
std::wstring不能直接用,得自己写循环或用std::erase(C++20 新增的基于值的擦除)
真正复杂的是混合条件 + 多容器类型 + 跨标准版本迁移。比如一个模板函数里想通用处理 vector/map/string,就得用 constexpr if + __cpp_lib_erase_if 宏判断,而不是假装它无处不在。










