Sobes.tech
Middle+

How does iterator invalidation occur in an unordered_map container?

sobes.tech AI

Answer from AI

Invalidation of iterators in std::unordered_map occurs when the hash table structure is changed or elements are removed.

Main cases:

  • Insertion: When inserting an element, rehashing (reallocation and restructuring of the table) may be required if the load factor exceeds max_load_factor(). In this case, all iterators, references, and pointers to elements become invalid. If rehashing does not occur, iterators to existing elements remain valid, but the iterator pointing to the end of the container (end()) may become invalid.
  • Deletion: Removing a single element using an iterator (erase(pos)) invalidates only the iterator pos and references/pointers to the removed element. Iterators to other elements remain valid. Removing a range of elements (erase(first, last)) invalidates all iterators, references, and pointers in the removed range. Using clear() or erasing by key (erase(key)) invalidates all iterators, references, and pointers to the removed elements. Iterators to other elements remain valid.
  • Rehashing (rehash): Explicit call to rehash() or automatic rehashing due to insertion invalidates all iterators, references, and pointers.
  • Reserving (reserve): Similar to rehashing, an explicit call to reserve() may cause reallocation and invalidate all iterators, references, and pointers.

It is important to remember that in unordered_map, the order of elements is not guaranteed, and the position of elements may change regardless of iterator invalidation.

#include <unordered_map>
#include <iostream>

int main() {
    std::unordered_map<int, std::string> my_map;
    my_map[1] = "one";
    my_map[2] = "two";

    auto it = my_map.begin(); // Iterator to beginning

    my_map[3] = "three"; // Insertion, may cause rehashing and invalidate `it`

    // Insertion without rehashing (e.g., if load_factor is low)
    // `it` may remain valid, but its position may change logically

    // auto it_to_erase = my_map.find(1);
    // if (it_to_erase != my_map.end()) {
    //     my_map.erase(it_to_erase); // Invalidates `it_to_erase`
    //     // Other iterators remain valid
    // }

    // my_map.clear(); // Invalidates all iterators

    return 0;
}