Understanding std::unordered_map in C++

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;

Tags: C++ STL unordered_map hash_table associative_container

Posted on Fri, 23 Oct 2026 16:44:19 +0000 by Afser