Tip of the Week #158: Abseil Associative containers and contains()

Originally posted as TotW #158 on January 3, 2019

By James Dennett

Updated 2020-04-20

Quicklink: abseil.io/tips/158

“I cannot contain myself” – Bertrand Russell

Does That Container Contain This Thing or Not?

When checking whether a set contains a value or a map contains a key, C++ has historically forced users to choose between writing the rather verbose

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

or the arguably obtuse (and sometimes inefficient)

container.count(value) != 0

instead of writing

container.contains(value)

as we’d like to.

container.contains(value) to the Rescue

The simpler syntax is part of the C++20 Standard, and Abseil’s (absl::{flat,node}_hash_{map,set}) and btree containers (absl::btree_*) support it today.

contains has the same support for heterogeneous lookup as find, so (for example) it’s possible to check whether an absl::flat_hash_set<std::string> contains an absl::string_view value without paying the costs of converting to a std::string object:

constexpr absl::string_view name = "Willard Van Orman Quine";
absl::flat_hash_set<std::string> names = {std::string(name)};
assert(names.contains(name));  // No dynamic allocation here.

Given that most of our code that needs associative containers (whether sets or maps) should be using the Abseil hashed containers today (see Tip #136), it should rarely be necessary to use one of the other formulations in new code.

NOTE: As described in Tip #132 (“Avoid Redundant Map Lookups”), don’t check if an item is in a container and then do another operation that implies a lookup (such as find, insert or remove).

Conclusion

Querying whether an item can be found in an associative container is a common operation, and a natural syntax for it is container.contains(value). Prefer that syntax when possible.


Subscribe to the Abseil Blog