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ż MyClass
nie 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 true
sytuacji, w której nastąpiło wstawienie i false
jeś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ć, pMyObj
nie 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ż pMyObj
pozostają 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 ++ .