当年写 STL。
你总会写一些“看起来很蠢,但必须写”的代码。
不是因为你不会。
是因为接口就只给你那么多。
当年:查一个 key 是否存在,要写 find + end
你写 std::unordered_map。
想问一句。
“有没有这个 key”。
你得这么写。
#include <unordered_map>
std::unordered_map<int, int> m;
bool has = (m.find(42) != m.end());
能跑。
但它不是一句话。
它更像一种仪式。
线上啪一下:你把 end 写错了,结果分支逻辑反了
这种事故很现实。
尤其是在复制粘贴之后。
!= 写成 ==。
或者你用了另一个容器的 end()。
上线后。
缓存命中率突然掉。
你排查半天。
发现只是“判断存在性”写错。
C++20:contains
C++20 给关联容器加了 contains。
你可以直接问。
bool has = m.contains(42);
这句话更像人话。
而且更不容易写反。
字符串也一样:starts_with / ends_with
当年你想判断前缀。
你可能这么写。
#include <string>
std::string s = "error: timeout";
bool ok = (s.rfind("error:", 0) == 0);
能用。
但读起来很费劲。
你得想一秒。
rfind 为啥能当 starts_with。
C++20:直接说 starts_with
#include <string>
bool ok = s.starts_with("error:");
你不用再解释。
代码自己会解释。
ends_with 也一样。
bool ok2 = s.ends_with("timeout");
erase_if:删元素别再手搓循环
当年你想按条件删除。
你会写一段 iterator 循环。
写得对不难。
但写错很致命。
尤其是迭代器失效。
C++20:erase_if
#include <string>
std::string s2 = "a1b2c3";
std::erase_if(s2, [](char c) { return c >= '0' && c <= '9'; });
它表达的就是。
“把满足条件的字符删掉”。
你不需要自己写 for。
也不需要自己处理 erase 的细节。
关键结论
这些小增强不酷。
但它们能帮你少写一堆容易出错的样板。
小结
contains 让“存在性”变成一句话。
starts_with/ends_with 让字符串意图更直观。
erase_if 让删除逻辑更少踩坑。