C++怎么使用erase_if_C++容器删除教程【简洁】

6次阅读

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

C++怎么使用erase_if_C++容器删除教程【简洁】

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::liststd::forward_listerase_if 后,仍按旧习惯检查 it != end() —— 实际已无迭代器参与,纯属多余

map/set 等关联容器不能直接用 erase_if 删除键值对

标准 erase_ifstd::mapstd::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 特化,参数是 charunsigned char,不是 std::string 子串匹配。

使用场景很明确:清洗字符。比如去空格、去控制符、转小写后删元音……

std::string s = "HellotWorldn"; std::erase_if(s, [](char c) { return std::isspace(static_cast<unsigned char>(c)); }); // s 变成 "HelloWorld"

容易踩的坑:

  • 忘记 static_cast<unsigned char></unsigned> 直接传 charstd::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 宏判断,而不是假装它无处不在。

text=ZqhQzanResources