每周技巧 #158:Abseil 关联容器和 `contains()`

本节阅读量:

本文翻译自 Abseil 官网的 Tip of the Week #158: Abseil Associative containers and contains()

原文最初作为 TotW #158 发布于 2019 年 1 月 3 日。

作者:James Dennett

更新于 2020 年 4 月 20 日。

快捷链接:abseil.io/tips/158

“我无法克制自己。” —— Bertrand Russell

那个容器到底包含这个东西吗?

检查 set 是否包含某个值,或 map 是否包含某个 key 时,C++ 历史上迫使用户在相当啰嗦的写法:

1
container.find(value) != container.end()

和可以说有些晦涩(有时还低效)的写法之间选择:

1
container.count(value) != 0

而不是写我们想写的:

1
container.contains(value)

container.contains(value) 来救场

这个更简单的语法是 C++20 标准的一部分,而 Abseil 的哈希容器(absl::{flat,node}_hash_{map,set})和 btree 容器(absl::btree_*)今天已经支持它。

containsfind 一样支持异构查找,所以(例如)可以检查 absl::flat_hash_set<std::string> 是否包含一个 absl::string_view 值,而不必付出转换为 std::string 对象的成本:

1
2
3
constexpr absl::string_view name = "Willard Van Orman Quine";
absl::flat_hash_set<std::string> names = {std::string(name)};
assert(names.contains(name));  // 这里没有动态分配。

鉴于我们大多数需要关联容器(无论 set 还是 map)的代码现在都应该使用 Abseil 哈希容器(见 技巧 #136),新代码中很少需要使用其他写法。

注意:如 技巧 #132(“避免冗余的 map 查找”)所述,不要先检查某项是否在容器中,然后再做另一个隐含查找的操作(例如 findinsertremove)。

结论

查询某个项是否能在关联容器中找到,是常见操作;它的自然语法是 container.contains(value)。可用时优先使用这个语法。

每周技巧 #153:不要使用 using 指示

上一节

每周技巧 #161:好的局部变量和坏的局部变量

下一节