TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #921 4.72K
Константная мапа
#новичкам

Определяете вы какое-нибудь отображение в коде:

using CommandCreator = std::function<std::unique_ptr<ICommand>(const std::vector<std::string>&)>;
const std::unordered_map<std::string, CommandCreator> commands = {
{"create", [](const std::vector<std::string>& vec){return std::make_unique<CreateCommand>(vec)}},
{"delete", [](const std::vector<std::string>& vec){return std::make_unique<DeleteCommand>(vec)}},
{"save", [](const std::vector<std::string>& vec){return std::make_unique<SaveCommand>(vec)}}
};


Никаких больше команд вы не обрабатываете, отображение константно.

И вот вы хотите получить доступ к элементам мапы:

auto command = commands[command_name](vec);
command->Execute();


И тут бац! И ошибка компиляции о том, что нет такого оператора[], который бы принимал константную std::unordered_map.

Почему так? У вектора же есть.

Проблема тут комплексная.

Здесь мы рассказали о том, что operator[] у мапы имеет одну особенность. Если вы ему передаете новый ключ, то он изменяет мапу и вставляет в нее элемент с этим новым ключом и дефолтным значением.

Это сделано по всей видимости по причине универсализации поведения между операторами[] для большинства контейнеров. Обычно operator[] не бросает никаких исключений. Он может приводить к неопределенному поведению, как например у вектора при доступе за границу массива. Но он не бросает.

И в случае мапы не очень понятно, что делать, если переданного ключа нет, бросать нельзя и хочется сохранить идентичность интерфейса по всему STL с возвратом ссылки.

Вот и решили конструировать объект налету.

Но для константного оператора вообще непонятно, что делать, если ключа нет, бросать нельзя, нужно возвращать ссылку, да еще и изменять мапу нельзя. И UB тоже не хочется, чем меньше его в стандарте, тем лучше.

Поэтому решили проблему гениально: вообще не вводить эту версию оператора.

В условиях отсутствия константного operator[] для std::map и std::unordered_map вы можете использовать либо метод at(), который бросает std::out_of_range, если ключа нет. Или find(), который вернет итератор на конец мапы:

auto command = commands.at(command_name)(vec);
command->Execute();
// or
if (auto it = commands.find(command_name); it != commands.end()) {
auto command = it->second();
command->Execute();
} else {
std::cout << "ERROR" << std::endl;
}


Find compromis. Stay cool.

#STL
  • ❤ 22
  • 👍 15
  • 🔥 8
  • 😱 1
More from @grokaemcpp
  1. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  2. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  3. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  4. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  5. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  6. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →