Std::map — добавление элемента с помощью оператора индекса против метода вставки

Я пытаюсь понять и убедиться, что три разных способа вставки элементов в std::map действительно одинаковы.

std::map<int, char> mymap;

Сразу после объявления mymap - будет ли вставка элемента со значением a для ключа 10 одним и тем же этими тремя способами?

  1. mymap[10]='a';

  2. mymap.insert(mymap.end(), std::make_pair(10, 'a'));

  3. mymap.insert(std::make_pair(10, 'a'));

В частности, имеет ли смысл использовать mymap.end(), когда в std::map нет существующего элемента?

Сейчас. 2 и 3 сделают то же самое. №1 отличается. Что происходит, когда в карте уже есть элемент с ключом 10?

Pete Becker 24.05.2019 10:25

Сборка для сравнения: godbolt.org/z/hw23oQ

pptaszni 24.05.2019 10:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
2
787
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Да, они фактически одинаковы. Сразу после объявления mymap все три метода превращают mymap в {10, 'a'}.

Можно использовать mymap.end(), когда в std::map нет существующего элемента. В данном случае это begin() == end(), что является универсальным способом обозначения пустого контейнера.

Они не совпадают — если на карте уже есть элемент с этим ключом, 1 будет вести себя иначе, чем 2 и 3.

Steve 24.05.2019 10:36

@ Стив Прочитай вопрос. Обратите особое внимание на «Сразу после объявления mymap».

L. F. 24.05.2019 10:36
Ответ принят как подходящий

Основное отличие состоит в том, что (1) сначала по умолчанию создает объект key на карте, чтобы иметь возможность вернуть ссылку на этот объект. Это позволяет вам присвоить ему что-то.

Имейте это в виду, если вы работаете с типами, которые хранятся в карте, но не имеют конструктора по умолчанию. Пример:

struct A {
   explicit A(int) {};
};

std::map<int, A> m;

m[10] = A(42); // Error! A has no default ctor

m.insert(std::make_pair(10, A(42))); // Ok
m.insert(m.end(), std::make_pair(10, A(42))); // Ok

Другое заметное отличие состоит в том, что (как указал @PeteBecker в комментариях) (1) перезаписывает существующие записи на карте, а (2) и (3) — нет.

(1) отличается от (2) и (3), если существует элемент с тем же ключом. (1) заменит элемент, где (2) и (3) произойдет сбой и вернет значение, обозначающее, что вставка не произошла.

(1) также требует, чтобы отображаемый тип был конструируемым по умолчанию. На самом деле (1) первое значение по умолчанию создает объект, если он еще не существует, и заменяет его указанным значением.

(2) и (3) также отличаются. Чтобы понять разницу, нам нужно понять, что делает итератор в (2). Из cppreference итератор ссылается на подсказку, где вставка происходит как можно ближе к этой подсказке. Существует разница в производительности в зависимости от достоверности подсказки. Цитата с той же страницы:

Amortized constant if the insertion happens in the position just after the hint, logarithmic in the size of the container otherwise.(until C++11)

Amortized constant if the insertion happens in the position just before the hint, logarithmic in the size of the container otherwise. (since C++11)

Таким образом, для больших карт мы можем получить прирост производительности, если каким-то образом уже знаем положение.

Сказав все это, если карта только что создана и вы выполняете операцию без предшествующих элементов на карте, как вы сказали в вопросе, то я бы сказал, что все три будут практически одинаковыми (хотя внутренняя работа будет другой как указано выше).

Другие вопросы по теме