Некоторое время назад у меня была дискуссия с коллегой о том, как вставить значения в карты STL . Я предпочел,
map[key] = value;
потому что это естественно и понятно для чтения, тогда как он предпочитал
map.insert(std::make_pair(key, value))
Я просто спросил его, и никто из нас не может вспомнить причину, по которой вставка лучше, но я уверен, что это был не просто стиль, а техническая причина, например, эффективность. Ссылка SGI STL просто говорит : «Строго говоря, эта функция - член не является необходимым: она существует только для удобства.»
Кто-нибудь может сказать мне эту причину, или я просто мечтаю, что она есть?
Ответы:
Когда пишешь
нет никакого способа узнать , если вы заменили на
value
FORkey
, или если вы создали новыйkey
сvalue
.map::insert()
создаст только:Для большинства моих приложений меня обычно не волнует, создаю я или заменяю, поэтому я использую более легкое для чтения
map[key] = value
.источник
(res.first)->second
а неvalue
и во втором случае.else
потому что я думаю, что использованиеvalue
яснее, чем итератор. Только если тип значения имеет необычный экземпляр ctor или op ==, он будет другим, и этот тип вызовет другие проблемы при использовании контейнеров STL, таких как map.map.insert(std::make_pair(key,value))
должно бытьmap.insert(MyMap::value_type(key,value))
. Тип, возвращаемый изmake_pair
, не соответствует типу, принятому в,insert
и текущее решение требует преобразованияoperator[]
, просто сравните размер до и после. Имхо возможность вызыватьmap::operator[]
только для конструируемых типов по умолчанию гораздо важнее.Они имеют разную семантику, когда дело доходит до ключа, уже существующего на карте. Так что они на самом деле не сопоставимы напрямую.
Но версия оператора [] требует создания значения по умолчанию, а затем присвоения, поэтому, если это дороже, чем копирование, то это будет дороже. Иногда конструкция по умолчанию не имеет смысла, и тогда было бы невозможно использовать версию operator [].
источник
Еще одна вещь, чтобы отметить с
std::map
:myMap[nonExistingKey];
создаст новую запись на карте, привязанную кnonExistingKey
инициализированному значению по умолчанию.Это испугало меня до чертиков, когда я впервые увидел это (пока бился головой об ужасно унаследованную ошибку). Не ожидал этого. Для меня это выглядит как операция get, и я не ожидал «побочного эффекта». Предпочитаю
map.find()
при получении с вашей карты.источник
Если снижение производительности конструктора по умолчанию не является проблемой, пожалуйста, ради бога, используйте более читаемую версию.
:)
источник
insert
Лучше с точки зрения безопасности.Выражение
map[key] = value
на самом деле две операции:map[key]
- создание элемента карты со значением по умолчанию.= value
- копирование значения в этот элемент.Исключение может произойти на втором этапе. В результате операция будет выполнена только частично (новый элемент был добавлен в карту, но этот элемент не был инициализирован с
value
). Ситуация, когда операция не завершена, но состояние системы изменено, называется операцией с «побочным эффектом».insert
операция дает надежную гарантию, означает, что она не имеет побочных эффектов ( https://en.wikipedia.org/wiki/Exception_safety ).insert
либо полностью выполнен, либо оставляет карту в неизмененном состоянии.http://www.cplusplus.com/reference/map/map/insert/ :
источник
Если ваше приложение критично к скорости, я посоветую использовать оператор [], поскольку он создает всего 3 копии исходного объекта, из которых 2 являются временными объектами и рано или поздно уничтожаются как.
Но в insert () создаются 4 копии исходного объекта, из которых 3 являются временными объектами (не обязательно «временными») и уничтожаются.
Что означает дополнительное время для: 1. Выделения памяти для одного объекта 2. Один дополнительный вызов конструктора 3. Один дополнительный вызов деструктора 4. Выделение памяти одного объекта
Если ваши объекты большие, конструкторы типичны, деструкторы много освобождают от ресурсов, а количество очков выше еще больше. Что касается читабельности, я думаю, что оба достаточно справедливы.
Тот же вопрос возник у меня в голове, но не над читаемостью, а над скоростью. Вот пример кода, с помощью которого я узнал о пункте, который я упомянул.
источник
insert
должен делать тот же поиск, так что нет никакой разницы с этим[]
(потому что ключи карты уникальны).Теперь в C ++ 11 я думаю, что лучший способ вставить пару в карту STL:
Результат будет пара с:
Первый элемент (result.first), указывает на вставленную пару или указывает на пару с этим ключом, если ключ уже существует.
Второй элемент (result.second), true, если вставка была правильной или ложной, что-то пошло не так.
PS: Если у вас нет дела по поводу заказа, вы можете использовать std :: unordered_map;)
Спасибо!
источник
Гвоздь с map :: insert () состоит в том, что он не заменит значение, если ключ уже существует на карте. Я видел код C ++, написанный Java-программистами, где они ожидали, что insert () будет вести себя так же, как Map.put () в Java, где значения заменяются.
источник
Обратите внимание, что вы также можете использовать Boost.Assign :
источник
Вот еще один пример, показывающий, что значение ключа
operator[]
перезаписывается, если оно существует, но.insert
не перезаписывает значение , если оно существует.источник
Это довольно ограниченный случай, но, судя по комментариям, которые я получил, думаю, стоит отметить.
Я видел людей в прошлом, использующих карты в форме
чтобы избежать случаев случайного перезаписи значения, а затем продолжить писать в некоторых других кусках кода:
Их причина сделать это, насколько я помню, заключалась в том, что они были уверены, что в этих определенных фрагментах кода они не будут перезаписывать значения карты; следовательно, идти вперед с более «читабельным» методом
[]
.На самом деле у меня никогда не было прямых проблем с кодом, написанным этими людьми, но до сегодняшнего дня я твердо чувствую, что риски - пусть даже небольшие - не должны приниматься, когда их легко избежать.
В случаях, когда вы имеете дело со значениями карты, которые абсолютно не должны быть перезаписаны, используйте
insert
. Не делайте исключений просто для удобства чтения.источник
insert
(неinput
), поскольку этоconst_cast
приведет к перезаписи любого предыдущего значения, что очень неконстантно. Или не помечайте тип значения какconst
. (Подобные вещи обычно являются конечным результатомconst_cast
, так что это почти всегда красный флаг, указывающий на ошибку где-то еще.)insert
в случаях, когда вы хотите предотвратить перезапись значений. (Только изменилinput
кinsert
- спасибо)const_cast<T>(map[key])
были: 1. [] более читабелен, 2. они уверены в определенных фрагментах кода, они не будут перезаписывать значения, и 3. они не делают хочу, чтобы другие биты кода ничего не знали, перезаписывая их значения - отсюда иconst value
.const_cast
кажется, более чем сводит на нет дополнительную «читабельность»[]
, и такого рода уверенности почти достаточно оснований, чтобы уволить разработчика. Сложные условия работы решаются пуленепробиваемыми конструкциями, а не внутренностями.Тот факт, что
insert()
функция std :: map не перезаписывает значение, связанное с ключом, позволяет нам писать код перечисления объектов следующим образом:Это довольно распространенная проблема, когда нам нужно сопоставить разные неуникальные объекты с некоторыми идентификаторами в диапазоне 0..N. Эти идентификаторы могут быть позже использованы, например, в алгоритмах графа. Альтернатива с
operator[]
будет выглядеть менее читабельным на мой взгляд:источник