Notes

Thoughts, write-ups, and things worth remembering.

Associative containers

#cpp#containers Updated Sep 16, 2026

Key-value lookup, instead of index-based like std::vector.

map / set — sorted, tree-based

std::map<std::string, int> scores;
scores["Alice"] = 100;                  // insert or update
scores.insert({"Bob", 90});              // insert, does nothing if key exists
scores.at("Alice");                      // 100, throws if missing
scores.find("Alice") != scores.end();    // check existence without inserting
scores.erase("Alice");

for (const auto& [name, score] : scores) { ... }   // iterates in sorted key order

Backed by a red-black tree — O(log n) for lookup, insert, and erase. Iterating a map always visits keys in sorted order, for free.

unordered_map — hash-based, faster average case, no ordering

std::unordered_map<std::string, int> scores;
scores["Alice"] = 100;   // same interface as map

Backed by a hash table instead — O(1) average-case lookup/insert/erase, but O(n) worst case if many keys collide into the same bucket. Iteration order is unspecified and can change between runs — never rely on it.

When to pick which

OrderTypical lookup
map / setsorted by keyO(log n)
unordered_map / unordered_setnoneO(1) average

Default to unordered_map for pure lookup speed. Reach for map when sorted iteration matters, or the key type doesn’t have a convenient hash readily available.

Gotcha: operator[] silently inserts

if (scores["Charlie"] > 50) { ... }   // "Charlie" didn't exist - it just got
                                        // inserted with value 0!

operator[] default-constructs a new entry if the key isn’t found — checking existence this way accidentally creates it. Use .find() or .count() to check without inserting.

std::vector basics