Od C ++ 17 std::map oferuje dwie nowe metody wstawiania: insert_or_assign()i try_emplace(), jak również wspomniano w komentarzu sp2danny .
insert_or_assign()
Zasadniczo insert_or_assign()jest to „ulepszona” wersja operator[]. W przeciwieństwie do operator[], insert_or_assign()nie wymaga, aby typ wartości mapy był domyślnym konstruowalnym. Na przykład poniższy kod nie jest kompilowany, ponieważ MyClassnie ma domyślnego konstruktora:
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;
}
Jeśli jednak zastąpisz myMap[0] = MyClass(1);ją następującym wierszem, kod zostanie skompilowany, a wstawienie nastąpi zgodnie z zamierzeniami:
myMap.insert_or_assign(0, MyClass(1));
Ponadto, podobnie jak insert(), insert_or_assign()zwraca pair<iterator, bool>. Wartość logiczna dotyczy truesytuacji, w której nastąpiło wstawienie i falsejeśli przypisanie zostało wykonane. Iterator wskazuje na element, który został wstawiony lub zaktualizowany.
try_emplace()
Podobnie jak powyżej, try_emplace()jest „ulepszeniem” emplace(). W przeciwieństwie do emplace(), try_emplace()nie modyfikuje swoich argumentów, jeśli wstawianie nie powiedzie się z powodu klucza już istniejącego w mapie. Na przykład poniższy kod próbuje umieścić element z kluczem, który jest już przechowywany w mapie (patrz *):
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;
}
Wyjście (przynajmniej dla VS2017 i Coliru):
pMyObj nie został wstawiony
pMyObj i tak został zmodyfikowany
Jak widać, pMyObjnie wskazuje już na oryginalny obiekt. Jeśli jednak zastąpisz auto [it, b] = myMap2.emplace(0, std::move(pMyObj));poniższym kodem, dane wyjściowe będą wyglądać inaczej, ponieważ pMyObjpozostają niezmienione:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
Wynik:
pMyObj nie został wstawiony
pMyObj pMyObj.m_i = 2
Kod na Coliru
Uwaga: starałem się, aby moje wyjaśnienia były jak najkrótsze i najprostsze, aby dopasować je do tej odpowiedzi. Aby uzyskać bardziej precyzyjny i wyczerpujący opis, polecam przeczytanie tego artykułu na temat Fluent C ++ .