В частном случае карты старых вариантов было только два: operator[]
и insert
(разныеinsert
). Поэтому я начну объяснять это.
operator[]
Является находкой или, добавить оператор. Он попытается найти элемент с заданным ключом внутри карты и, если он существует, вернет ссылку на сохраненное значение. Если этого не произойдет, он создаст новый элемент, вставленный на место с инициализацией по умолчанию, и вернет ссылку на него.
insert
Функция (в единственном элементе аромата) занимает value_type
( std::pair<const Key,Value>
), он использует ключ ( first
элемент) и пытается вставить ее. Потому std::map
что не допускает дублирования, если есть существующий элемент, он ничего не вставит.
Первое различие между ними заключается в том, что operator[]
необходимо иметь возможность создавать инициализированное значение по умолчанию , и поэтому оно непригодно для типов значений, которые не могут быть инициализированы по умолчанию. Второе различие между ними заключается в том, что происходит, когда уже есть элемент с данным ключом. insert
Функция не будет изменять состояние карты, но вместо того, чтобы вернуть итератор к элементу (и false
о том , что она не была установлена).
// assume m is std::map<int,int> already has an element with key 5 and value 0
m[5] = 10; // postcondition: m[5] == 10
m.insert(std::make_pair(5,15)); // m[5] is still 10
В случае insert
аргумента это объект value_type
, который может быть создан по-разному. Вы можете напрямую сконструировать его с соответствующим типом или передать любой объект, из которого value_type
может быть сконструирован объект , и именно здесь он std::make_pair
вступает в игру, поскольку он позволяет легко создавать std::pair
объекты, хотя это, вероятно, не то, что вы хотите ...
Чистый эффект от следующих вызовов аналогичен :
K t; V u;
std::map<K,V> m; // std::map<K,V>::value_type is std::pair<const K,V>
m.insert( std::pair<const K,V>(t,u) ); // 1
m.insert( std::map<K,V>::value_type(t,u) ); // 2
m.insert( std::make_pair(t,u) ); // 3
Но на самом деле это не одно и то же ... [1] и [2] на самом деле эквивалентны. В обоих случаях код создает временный объект того же типа ( std::pair<const K,V>
) и передает его insert
функции. insert
Функция создает соответствующий узел в бинарном дереве поиска , а затем скопировать value_type
часть из аргумента в узел. Преимущество использования value_type
в том, что, ну, value_type
всегда совпадает value_type
, вы не можете неправильно набирать тип std::pair
аргументов!
Разница в [3]. Функция std::make_pair
представляет собой шаблонную функцию, которая создаст std::pair
. Подпись:
template <typename T, typename U>
std::pair<T,U> make_pair(T const & t, U const & u );
Я намеренно не предоставил аргументы шаблона std::make_pair
, так как это обычное использование. И подразумевается, что аргументы шаблона выводятся из вызова, в данном случае T==K,U==V
, так что вызов std::make_pair
возвратит std::pair<K,V>
(обратите внимание на отсутствие const
). Для подписи требуется, value_type
чтобы она была близка, но не совпадала с возвращаемым значением из вызова std::make_pair
. Поскольку он достаточно близко, он создаст временный объект правильного типа и скопирует его, инициализирует. Это, в свою очередь, будет скопировано в узел, создав в общей сложности две копии.
Это можно исправить, указав аргументы шаблона:
m.insert( std::make_pair<const K,V>(t,u) ); // 4
Но это все равно подвержено ошибкам так же, как и явная типизация в случае [1].
До этого момента у нас были разные способы вызова, insert
которые требуют value_type
внешнего создания и копирования этого объекта в контейнер. В качестве альтернативы вы можете использовать, operator[]
если тип является конструируемым и назначаемым по умолчанию (преднамеренно фокусируясь только в m[k]=v
), и это требует инициализации по умолчанию одного объекта и копии значения в этот объект.
В C ++ 11 с использованием шаблонов с переменным числом строк и совершенной пересылки существует новый способ добавления элементов в контейнер посредством размещения (создания на месте). Эти emplace
функции в различных контейнерах делают в основном то же самое: вместо того , чтобы получить источник , из которого скопировать в контейнер, функция принимает параметры , которые будут переданы в конструктор объекта , хранящегося в контейнере.
m.emplace(t,u); // 5
В работе [5], std::pair<const K, V>
не создаются и передаются emplace
, а скорее ссылки на t
и u
объект передаются , emplace
который пересылает их в конструктор value_type
подобъекта внутри структуры данных. В этом случае нет Копии std::pair<const K,V>
не выполняются вообще, что является преимуществом emplace
над C ++ 03 альтернатив. Как и в случае с insert
ним не будет переопределять значение на карте.
Интересный вопрос, о котором я не задумывался, заключается в том, как на emplace
самом деле его можно реализовать для карты, и это не простая проблема в общем случае.