每周技巧 #136:无序容器

本节阅读量:

本文翻译自 Abseil 官网的 Tip of the Week #136: Unordered Containers

原文最初作为 TotW #136 发布于 2017 年 6 月 23 日。

作者:Matt Kulukundis

更新于 2020 年 4 月 6 日。

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

“有时,当材料真的很好时,你会给自己设下期待,想把它做成尽可能好的演出。你不只是端上普通杂烩,完成工作然后回家。” —— Peter Dinklage

TL;DR:官方且最新的建议见 https://abseil.io/docs/cpp/guides/container。本技巧介绍了这些新类型,但不是权威参考。

介绍 absl::*_hash_map

这里来了一组新的关联容器家族。它们提升了效率,并提前提供了 C++17 中的一些 API。它们还让开发者可以直接控制其实现和默认哈希函数,这对代码库的长期演进很重要。新代码应优先使用这些类型,而不是 std::unordered_map。这个家族中的所有 map 和 set API 都与 std::unordered_map 几乎相同,因此迁移到它们很容易。

每个 absl::*_hash_map 也都有对应的 absl::*_hash_set;不过,图示只会展示 map 情况,文中也常常只提 map

absl::flat_hash_mapabsl::flat_hash_set

它们应该是你的默认选择。它们把 value_type 存储在主数组内部。由于 rehash 时会移动数据,元素不具备指针稳定性。如果你需要指针稳定性,或者 value 很大,可以考虑改用 absl::node_hash_map,或者也许使用 absl::flat_hash_map<Key, std::unique_ptr<Value>>

警告:由于 rehash() 后指针不稳定,像 map["a"] = map["b"] 这样的代码会访问已失效内存。

absl::node_hash_mapabsl::node_hash_set

它们在主数组之外的节点中分配 value_type(类似 std::unordered_map)。由于单独分配,它们为已存储数据提供指针稳定性(map 中对象的地址不会改变),并且空槽只需要 8 字节。此外,它们可以存储既不可移动也不可复制的东西。

我们通常建议使用 absl::flat_hash_map<K, std::unique_ptr<V>>,而不是 absl::node_hash_map<K, V>;对 node_hash_set 也类似。

每周技巧 #135:测试契约,而不是实现

上一节

每周技巧 #140:常量:安全惯用法

下一节