Introduction to std::unordered_map
std::unordered_map is an associative container that holds unique key-value pairs. It offers average constant-time complexity for search, removal, and insertion operations. Unlike ordered maps, unordered_map does not store elements in any specific order. Instead, elements are placed into buckets determined by the hash value of their keys.
template<
class Key,
class T,
class Hash = std::hash<Key>,
class KeyEqual = std::equal_to<Key>,
class Allocator = std::allocator<std::pair<const Key, T>>
> class unordered_map;
Construction and Assignment
Constructors
An unordered_map can be constructed in various ways, such as creating a empty map, initializing it with an initializer list, copying from another map, or using iterators to copy a range of elements. You can also specify the minimum number of buckets, a custom hash function, an equality comparison function, or an allocator during construction.
// Create an empty map
std::unordered_map<std::string, int> emptyMap;
// Initialize with an initializer list
std::unordered_map<std::string, int> initialData{
{"apple", 1}, {"banana", 2}, {"cherry", 3}
};
// Copy constructor
std::unordered_map<std::string, int> copiedMap(initialData);
// Range constructor (copy first two elements)
std::unordered_map<std::string, int> partialMap(
initialData.begin(), std::next(initialData.begin(), 2)
);
std::cout << "emptyMap size = " << emptyMap.size() << std::endl;
std::cout << "initialData size = " << initialData.size() << std::endl;
std::cout << "copiedMap size = " << copiedMap.size() << std::endl;
std::cout << "partialMap size = " << partialMap.size() << std::endl;
Custom Hash and Equality Functions
For custom data types used as keys, you must define a hash function and an equality comparison function.
struct Person {
std::string name;
int age;
};
struct PersonHash {
std::size_t operator()(const Person& p) const {
// Combine hashes of name and age
return std::hash<std::string>()(p.name) ^ std::hash<int>()(p.age);
}
};
struct PersonEqual {
bool operator()(const Person& lhs, const Person& rhs) const {
return lhs.name == rhs.name && lhs.age == rhs.age;
}
};
std::unordered_map<Person, std::string, PersonHash, PersonEqual> peopleMap;
Destructor
When an unordered_map is destroyed, the destructors for all its elements are called.
struct Resource {
Resource(int id) : id_(id) {}
~Resource() {
std::cout << "Resource " << id_ << " destroyed." << std::endl;
}
int id_;
};
struct ResourceHash {
std::size_t operator()(const Resource& r) const {
return std::hash<int>()(r.id_);
}
};
struct ResourceEqual {
bool operator()(const Resource& lhs, const Resource& rhs) const {
return lhs.id_ == rhs.id_;
}
};
{
std::unordered_map<Resource, std::string, ResourceHash, ResourceEqual> resourceMap;
resourceMap.emplace(Resource(101), "Data A");
resourceMap.emplace(Resource(102), "Data B");
std::cout << "Scope ending." << std::endl;
}
// Destructors for Resource(101) and Resource(102) are called here
Assignment Operators
You can assign the contents of one unordered_map to another, either from another map or using an initializer list.
std::unordered_map<std::string, double> sourceMap{
{"pi", 3.14159}, {"e", 2.71828}
};
std::unordered_map<std::string, double> targetMap1;
std::unordered_map<std::string, double> targetMap2;
targetMap1 = sourceMap;
targetMap2 = {{"pi", 3.14}};
std::cout << "targetMap1 size = " << targetMap1.size() << std::endl;
std::cout << "targetMap2 size = " << targetMap2.size() << std::endl;
Iterators
The begin and cbegin member functions return iterators pointing to the first element, while end and cend point to the position just after the last element.
std::unordered_map<int, std::string> dataMap{
{10, "ten"}, {20, "twenty"}, {30, "thirty"}
};
// Modify values using a non-const iterator
for (auto it = dataMap.begin(); it != dataMap.end(); ++it) {
it->second = "Value: " + std::to_string(it->first);
}
// Read values using a const iterator
for (auto it = dataMap.cbegin(); it != dataMap.cend(); ++it) {
std::cout << "Key: " << it->first << ", Value: " << it->second << std::endl;
}
Capacity
empty
The empty member function checks if the container has no elements.
std::unordered_map<char, std::string> filledMap{{'a', "alpha"}};
std::unordered_map<char, std::string> emptyMap;
std::cout << std::boolalpha;
std::cout << "filledMap is empty: " << filledMap.empty() << std::endl;
std::cout << "emptyMap is empty: " << emptyMap.empty() << std::endl;
size
The size member function returns the number of elements in the container.
std::unordered_map<std::string, int> inventory{{"sword", 1}, {"shield", 1}};
std::cout << "Inventory contains " << inventory.size() << " items." << std::endl;