У конкретному випадку на карті старих варіантів було лише два: 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насправді реалізувати карту, і це не є простою проблемою в загальному випадку.