Poiché C ++ 17 std::map
offre due nuovi metodi di inserimento: insert_or_assign()
e try_emplace()
, come menzionato anche nel commento di sp2danny .
insert_or_assign()
Fondamentalmente, insert_or_assign()
è una versione "migliorata" di operator[]
. Al contrario operator[]
, insert_or_assign()
non richiede che il tipo di valore della mappa sia costruibile di default. Ad esempio, il codice seguente non viene compilato, perché MyClass
non ha un costruttore predefinito:
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;
}
Tuttavia, se si sostituisce myMap[0] = MyClass(1);
con la riga seguente, il codice viene compilato e l'inserimento avviene come previsto:
myMap.insert_or_assign(0, MyClass(1));
Inoltre, in modo simile a insert()
, insert_or_assign()
restituisce a pair<iterator, bool>
. Il valore booleano è true
se si è verificato un inserimento e false
se è stata eseguita un'assegnazione. L'iteratore punta all'elemento che è stato inserito o aggiornato.
try_emplace()
Simile a quanto sopra, try_emplace()
è un "miglioramento" di emplace()
. Al contrario emplace()
, try_emplace()
non modifica i suoi argomenti se l'inserimento fallisce a causa di una chiave già esistente nella mappa. Ad esempio, il codice seguente tenta di posizionare un elemento con una chiave già memorizzata nella mappa (vedere *):
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;
}
Output (almeno per VS2017 e Coliru):
pMyObj non è stato inserito
pMyObj è stato comunque modificato
Come puoi vedere, pMyObj
non punta più all'oggetto originale. Tuttavia, se si sostituisce auto [it, b] = myMap2.emplace(0, std::move(pMyObj));
con il codice seguente, l'output ha un aspetto diverso, perché pMyObj
rimane invariato:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
Produzione:
pMyObj non è stato inserito
pMyObj pMyObj.m_i = 2
Codice su Coliru
Nota: ho cercato di mantenere le mie spiegazioni il più brevi e semplici possibile per inserirle in questa risposta. Per una descrizione più precisa e completa, consiglio di leggere questo articolo su Fluent C ++ .