Хранятся ли объекты в std::unordered_map в порядке добавления?

Ответ

Нет. std::unordered_map — это хэш-таблица, и порядок её элементов не гарантируется. Он зависит от хэш-функции, внутренней структуры бакетов (корзин) и может меняться при рехэшировании (например, при увеличении размера контейнера).

Пример:

#include <iostream>
#include <unordered_map>
#include <string>

int main() {
    std::unordered_map<int, std::string> map;

    // Вставка в порядке возрастания ключа
    map.insert({3, "three"});
    map.insert({1, "one"});
    map.insert({4, "four"});
    map.insert({2, "two"});

    std::cout << "Iteration order:n";
    for (const auto& [key, value] : map) {
        std::cout << key << ": " << value << 'n';
    }
    // Вывод может быть, например: 2: two, 4: four, 1: one, 3: three
    // Порядок не соответствует ни порядку добавления, ни сортировке по ключу.
}

Альтернативы, если порядок важен:

  1. std::map — хранит элементы, отсортированные по ключу (логарифмический доступ).
  2. std::vector<std::pair<Key, Value>> — сохраняет порядок вставки, но поиск линейный.
  3. Комбинация структур — например, std::unordered_map<Key, Value> для быстрого поиска + std::vector<Key> для сохранения порядка.

Ответ 18+ 🔞

А, ну это же классика, ёпта! Смотри, тут всё просто, как два пальца об асфальт. std::unordered_map — это по сути своей обычная хэш-таблица, хитрая жопа, которая хранит данные как бог на душу положит. Порядок элементов там — это пиздец полный, никаких гарантий тебе не светит.

Представь, ты закидываешь в неё ключи по порядку: один, два, три. А когда начинаешь перебирать, она тебе может выдать: три, один, два. Или вообще: два, три, один. Всё зависит от её внутренней кухни — от хэш-функции, от того, как она там бакеты раскладывает. А если она ещё и рехэшируется (ну, когда места мало становится), так там вообще волнение ебать — порядок может враз поменяться.

Вот, глянь, наглядный пример:

#include <iostream>
#include <unordered_map>
#include <string>

int main() {
    std::unordered_map<int, std::string> map;

    // Кидаем по порядку, с тройки на двойку
    map.insert({3, "three"});
    map.insert({1, "one"});
    map.insert({4, "four"});
    map.insert({2, "two"});

    std::cout << "А теперь смотрим, в каком порядке она нам отдаст:n";
    for (const auto& [key, value] : map) {
        std::cout << key << ": " << value << 'n';
    }
    // И тут может вылезти что угодно! Например: 2: two, 4: four, 1: one, 3: three
    // Никакой логики, ни по ключу, ни по вставке. Полный пиздец.
}

Так что же делать, если порядок всё-таки нужен? Ну, варианты есть, конечно.

  1. std::map — вот это уже серьёзный парень. Он хранит всё отсортированным по ключу, всегда аккуратно. Но за красоту платишь скоростью — доступ там логарифмический, не мгновенный.
  2. std::vector<std::pair<Key, Value>> — самый простой и честный способ. Всё лежит ровно в том порядке, в каком ты засунул. Но искать в этой куче — это отдельный вид спорта, линейный поиск, овердохуища времени уйдёт.
  3. Сделать велосипед — то есть взять две структуры. Одна (std::unordered_map) для быстрого поиска по ключу, а вторая (например, std::vector) — чтобы просто запоминать, в каком порядке ты эти ключи добавлял. Ну, или взять готовую библиотеку, где это уже сделано. В общем, если нужен порядок — unordered_map тебе не друг, это точно.