I have identified four different ways of inserting elements into a std::map:
std::map function;
function[0] = 42;
function.inse
Since C++17 std::map offers two new insertion methods: insert_or_assign() and try_emplace(), as also mentioned in the comment by sp2danny.
insert_or_assign()Basically, insert_or_assign() is an "improved" version of operator[]. In contrast to operator[], insert_or_assign() doesn't require the map's value type to be default constructible. For example, the following code doesn't compile, because MyClass does not have a default constructor:
class MyClass {
public:
MyClass(int i) : m_i(i) {};
int m_i;
};
int main() {
std::map 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;
}
However, if you replace myMap[0] = MyClass(1); by the following line, then the code compiles and the insertion takes place as intended:
myMap.insert_or_assign(0, MyClass(1));
Moreover, similar to insert(), insert_or_assign() returns a pair. The Boolean value is true if an insertion occurred and false if an assignment was done. The iterator points to the element that was inserted or updated.
try_emplace()Similar to the above, try_emplace() is an "improvement" of emplace(). In contrast to emplace(), try_emplace() doesn't modify its arguments if insertion fails due to a key already existing in the map. For example, the following code attempts to emplace an element with a key that is already stored in the map (see *):
int main() {
std::map> myMap2;
myMap2.emplace(0, std::make_unique(1));
auto pMyObj = std::make_unique(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 (at least for VS2017 and Coliru):
pMyObj was not inserted
pMyObj was modified anyway
As you can see, pMyObj no longer points to the original object. However, if you replace auto [it, b] = myMap2.emplace(0, std::move(pMyObj)); by the the following code, then the output looks different, because pMyObj remains unchanged:
auto [it, b] = myMap2.try_emplace(0, std::move(pMyObj));
Output:
pMyObj was not inserted
pMyObj pMyObj.m_i = 2
Code on Coliru
Please note: I tried to keep my explanations as short and simple as possible to fit them into this answer. For a more precise and comprehensive description, I recommend reading this article on Fluent C++.