HOWTO · C++
How to Use HashMap in C++
This tutorial provides explanation on how to use Hashmaps in a proper way by explaining about std::map and std::unordered_map in C++. This also identifies the key differences and the best way to use Hashmaps in C++.
On this page
In C++, a hash map is provided by std::unordered_map; std::map is a related key-value container that keeps keys ordered. Both are associative containers: each key is unique and identifies one mapped value. Different keys may hold the same value. Use either when you need lookup by key, and choose based on whether ordered traversal matters.
The standard does not prescribe a specific internal implementation for std::map. Its observable ordering comes from its key comparison (ascending order with the default comparator). By contrast, std::unordered_map uses a hash function and buckets, and its iteration order is unspecified. Do not rely on the order you happen to see in one run.
How Hash Maps Work in C++
Include <map> or <unordered_map> and declare the key and mapped-value types, such as std::map<int, std::string>. insert adds a key-value pair only if the key is absent; assigning through operator[] inserts a value-initialized mapped value when needed, then assigns to it. For a scalar mapped type such as int, value-initialization produces zero before the assignment. Assigning to an existing key updates its value without creating a duplicate key. Use find when you need to check for a key before using its value. at also looks up a key, but reports a missing key with std::out_of_range.
The supplied runtime record shows successful execution of both original examples. The std::map output below is the recorded output; the unordered example later adds a traversal loop, so no output sequence is claimed for that revised example.
Use std::map for Ordered Keys
Use std::map when the keys should be traversed in comparator order or when you need ordered operations such as finding the first key at or after a value. Its search, insertion, and removal operations take logarithmic time, O(log n), where n is the number of elements. This predictable cost and ordered traversal are useful for reports, ranges, and sorted listings. The standard guarantees the ordering behavior, not a particular tree implementation.
Run this example:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<int, std::string> players;
players.emplace(2, "Lin Dan");
players.emplace(1, "Chen Long");
const auto found = players.find(1);
if (found != players.end()) {
std::cout << found->first << ": " << found->second << '\n';
}
for (const auto& entry : players) {
std::cout << entry.first << ": " << entry.second << '\n';
}
}
1: Chen Long
1: Chen Long
2: Lin Dan
The lookup prints key 1; the loop visits keys in comparator order, so 1 precedes 2 regardless of insertion order.
Use std::unordered_map for Hash-Based Lookup
Choose std::unordered_map when key lookup is the priority and sorted traversal is unnecessary. Search, insertion, and removal are average O(1) operations, but can take O(n) in the worst case, including when many keys collide. Rehashing can also change iteration order and invalidate iterators. The container maintains its own hash and equality requirements: equivalent keys must produce equal hash values.
Run this example:
#include <iostream>
#include <string>
#include <unordered_map>
int main() {
std::unordered_map<std::string, int> scores;
scores["Ada"] = 8;
scores["Lin"] = 11;
const auto found = scores.find("Ada");
if (found != scores.end()) {
std::cout << found->first << ": " << found->second << '\n';
}
for (const auto& entry : scores) {
std::cout << entry.first << ": " << entry.second << '\n';
}
std::cout << "Players: " << scores.size() << '\n';
}
The range-based loop traverses every entry in scores. Its entries may appear in any order, and neither the standard nor this example guarantees a particular sequence. Sort a separate list of keys if presentation order is required.
Choose Between std::map and std::unordered_map
| Need | std::map |
std::unordered_map |
|---|---|---|
| Traversal | Keys follow the comparator order | No iteration order is guaranteed |
| Search, insertion, removal | O(log n) |
Average O(1), worst case O(n) |
| Useful when | You need sorted output, ordered ranges, or predictable logarithmic operations | You need key-based lookup and do not need sorted traversal |
| Key requirements | A strict weak ordering via the comparator | A hash function and equality comparison consistent with each other |
For a word-frequency count or a cache where order is irrelevant, std::unordered_map is often a natural choice. Use std::map for sorted output or range queries by key. If an unordered container fits lookup but you need sorted presentation, collect and sort the keys before printing instead of assuming its iteration order. The choice depends on required behavior as well as average speed: benchmark with representative data if performance is important to your application.
Both containers support key-value access, but their iteration and performance guarantees differ. For a traversal that must produce keys in order, use std::map; for hash-based lookup where order does not matter, use std::unordered_map. For a separate example of ordered traversal, see inorder traversal in C++.