Я пытаюсь понять и убедиться, что три разных способа вставки элементов в std::map действительно одинаковы.
std::map<int, char> mymap;
Сразу после объявления mymap - будет ли вставка элемента со значением a для ключа 10 одним и тем же этими тремя способами?
mymap[10]='a';
mymap.insert(mymap.end(), std::make_pair(10, 'a'));
mymap.insert(std::make_pair(10, 'a'));
В частности, имеет ли смысл использовать mymap.end(), когда в std::map нет существующего элемента?
Сборка для сравнения: godbolt.org/z/hw23oQ





Да, они фактически одинаковы. Сразу после объявления mymap все три метода превращают mymap в {10, 'a'}.
Можно использовать mymap.end(), когда в std::map нет существующего элемента. В данном случае это begin() == end(), что является универсальным способом обозначения пустого контейнера.
Они не совпадают — если на карте уже есть элемент с этим ключом, 1 будет вести себя иначе, чем 2 и 3.
@ Стив Прочитай вопрос. Обратите особое внимание на «Сразу после объявления mymap».
Основное отличие состоит в том, что (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)
Таким образом, для больших карт мы можем получить прирост производительности, если каким-то образом уже знаем положение.
Сказав все это, если карта только что создана и вы выполняете операцию без предшествующих элементов на карте, как вы сказали в вопросе, то я бы сказал, что все три будут практически одинаковыми (хотя внутренняя работа будет другой как указано выше).
Сейчас. 2 и 3 сделают то же самое. №1 отличается. Что происходит, когда в карте уже есть элемент с ключом 10?