Оскільки C ++ 17 std::map
пропонує два нові способи вставки: insert_or_assign()
і try_emplace()
, як також згадується у коментарі sp2danny .
insert_or_assign()
В основному, insert_or_assign()
це "вдосконалена" версія operator[]
. На відміну від цього operator[]
, insert_or_assign()
не вимагає, щоб тип значення карти був конструктованим за замовчуванням. Наприклад, наступний код не компілюється, оскільки MyClass
не має конструктора за замовчуванням:
class MyClass {
public:
MyClass(int i) : m_i(i) {};
int m_i;
};
int main() {
std::map<int, MyClass> myMap;
// VS2017: "C2512: 'MyClass::MyClass' : no appropriate default constructor available"
// Coliru: "error: no matching function for call to 'MyClass::MyClass()"
myMap[0] = MyClass(1);
return 0;
}
Однак якщо ви заміните myMap[0] = MyClass(1);
наступний рядок, код збирається, а вставка відбувається за призначенням:
myMap.insert_or_assign(0, MyClass(1));
Більше того, подібний до insert()
, insert_or_assign()
повертає a pair<iterator, bool>
. Булеве значення - це true
якщо вставка і false
якщо було виконано призначення. Ітератор вказує на елемент, який був вставлений або оновлений.
try_emplace()
Подібним до вищесказаного try_emplace()
є "поліпшення" emplace()
. На відміну від emplace()
, try_emplace()
не змінює своїх аргументів, якщо вставка не вдається через ключ, який вже існує на карті. Наприклад, наступний код намагається замінити елемент ключем, який вже зберігається на карті (див. *):
int main() {
std::map<int, std::unique_ptr<MyClass>> myMap2;
myMap2.emplace(0, std::make_unique<MyClass>(1));
auto pMyObj = std::make_unique<MyClass>(2);
auto [it, b] = myMap2.emplace(0, std::move(pMyObj)); // *
if (!b)
std::cout << "pMyObj was not inserted" << std::endl;
if (pMyObj == nullptr)
std::cout << "pMyObj was modified anyway" << std::endl;
else
std::cout << "pMyObj.m_i = " << pMyObj->m_i << std::endl;
return 0;
}
Вихід (принаймні для VS2017 та Coliru):
pMyObj не було вставлено
pMyObj було змінено
Як бачите, pMyObj
більше не вказує на оригінальний об’єкт. Однак якщо замінити auto [it, b] = myMap2.emplace(0, std::move(pMyObj));
наступним кодом, то результат виглядає інакше, оскільки pMyObj
залишається незмінним:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
Вихід:
pMyObj не було вставлено
pMyObj pMyObj.m_i = 2
Код про Коліру
Зверніть увагу: я намагався зробити свої пояснення максимально короткими та простими, щоб вписати їх у цю відповідь. Для більш точного та вичерпного опису рекомендую прочитати цю статтю на Fluent C ++ .