У конкретному випадку на карті старих варіантів було лише два: operator[]
і insert
(різні смаки insert
). Тож я почну пояснювати це.
The 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
- це шаблонна функція, яка створить a 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
насправді реалізувати карту, і це не є простою проблемою в загальному випадку.