Назад к вопросам
Middle
130
questionbank

Инвалидирует ли операция с unordered_map итераторы?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

Да, некоторые операции инвалидируют итераторы unordered_map.

  • Вставка элемента (insert, emplace, try_emplace, insert_or_assign) может инвалидировать все итераторы, если она приводит к перехешированию контейнера (увеличению количества корзин и перераспределению элементов). Если перехеширования не происходит, итераторы остаются действительными.
  • Удаление элемента (erase) инвалидирует итератор, указывающий на удаленный элемент, и может инвалидировать другие итераторы в той же корзине, если внутренняя организация корзины меняется. Итераторы на элементы в других корзинах остаются действительными.
  • clear(): Инвалидирует все итераторы.
  • rehash() и reserve(): Явно вызывают перехеширование и инвалидируют все итераторы.

Пример, демонстрирующий инвалидацию при перехешировании после вставки:

#include <unordered_map>
#include <iostream>

int main() {
    std::unordered_map<int, int> map;
    map.reserve(5); // Зарезервируем место, чтобы первое время не было перехеширования

    map[1] = 10;
    map[2] = 20;

    auto it = map.find(1); // Итератор на элемент 1

    std::cout << "Before insert_or_assign: " << it->first << std::endl;

    // Вставка, которая может вызвать перехеширование, если размер превысит current_load_factor * bucket_count
    // Добавим много элементов, чтобы гарантировать перехеширование
    for (int i = 3; i < 100; ++i) {
        map[i] = i * 10;
    }

    // Попытка использовать старый итератор после потенциального перехеширования
    // Это undefined behavior, но для демонстрации:
    // std::cout << "After insert_or_assign: " << it->first << std::endl; // Опасно!

    // После операции, которая могла инвалидировать итератор, его нельзя безопасно использовать.
    // Необходимо получить новый итератор:
    it = map.find(1);
    if (it != map.end()) {
         std::cout << "After insert_or_assign (new iterator): " << it->first << std::endl;
    }

    return 0;
}

Следует всегда получать новый итератор после операций, которые могут его инвалидировать, чтобы избежать неопределенного поведения.