Já que C ++ 17 std::map oferece dois novos métodos de inserção: insert_or_assign()e try_emplace(), como também mencionado no comentário de sp2danny .
insert_or_assign()
Basicamente, insert_or_assign()é uma versão "aprimorada" do operator[]. Em contraste com operator[], insert_or_assign()não exige que o tipo de valor do mapa seja construtível por padrão. Por exemplo, o código a seguir não é compilado, porque MyClassnão tem um construtor padrão:
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;
}
No entanto, se você substituir myMap[0] = MyClass(1);pela linha a seguir, o código será compilado e a inserção ocorrerá conforme o esperado:
myMap.insert_or_assign(0, MyClass(1));
Além disso, semelhante a insert(), insert_or_assign()retorna a pair<iterator, bool>. O valor booleano é truese uma inserção ocorreu e falsese uma atribuição foi feita. O iterador aponta para o elemento que foi inserido ou atualizado.
try_emplace()
Semelhante ao anterior, try_emplace()é uma "melhoria" de emplace(). Em contraste com emplace(), try_emplace()não modifica seus argumentos se a inserção falhar devido a uma chave já existente no mapa. Por exemplo, o código a seguir tenta substituir um elemento por uma chave que já está armazenada no mapa (consulte *):
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;
}
Saída (pelo menos para VS2017 e Coliru):
pMyObj não foi inserido
pMyObj foi modificado de qualquer maneira
Como você pode ver, pMyObjnão aponta mais para o objeto original. No entanto, se você substituir auto [it, b] = myMap2.emplace(0, std::move(pMyObj));pelo código a seguir, a saída parecerá diferente, porque pMyObjpermanece inalterada:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
Resultado:
pMyObj não foi inserido
pMyObj pMyObj.m_i = 2
Código em Coliru
Observação: tentei manter minhas explicações o mais curtas e simples possível para encaixá-las nessa resposta. Para uma descrição mais precisa e abrangente, recomendo a leitura deste artigo sobre Fluent C ++ .