C++17 introduces the try_emplace
method for std::map
, so now I can write code like below:
struct Test
{
Test(int i, int j){}
};
std::map<int, Test> tmap;
tmap.try_emplace(10, 10, 10);
But there is no try_emplace
for std::multimap<int, Test>
, so piecewise_construct
is still needed.
Is there a technical reason for this?
multimap size () function in C++ STL – Returns the number of elements in the multimap container. multimap::emplace () in C++ STL – Inserts the key and its element in the multimap container. multimap::begin () and multimap::end () in C++ STL – begin () returns an iterator referring to the first element in the multimap container.
Inserts a new element into the container constructed in-place with the given args . Careful use of emplace allows the new element to be constructed while avoiding unnecessary copy or move operations.
Multimap in C++ Standard Template Library (STL) Multimap is similar to map with an addition that multiple elements can have same keys. Rather than each element being unique, the key value and mapped value pair has to be unique in this case.
In this article, we are going to learn try_emplace method in Maps and Unordered Maps. This method was added in C++17 (i.e gcc 9.1) version. This new function proposed behaves similarly to emplace (), but has an advantage that is, it will not construct the object associated with the key, if the key already exists.
is there a technical reason for this?
Yes. The purpose of try_emplace()
is to not do anything if the key already exists in the map. But for std::{unordered_,}multi{map,set}
, you can have multiple values for each key. That is, indeed, the point of these containers: to have multiple values for a given key.
As a result, try_emplace()
cannot fail for these containers - so it would be confusing and pointless to provide such a function.
Based on the comments, it seems that the motivation is just the part of try_emplace()
that makes it easier to emplace a value. You can write a helper function for that:
template <typename Map, typename Key, typename... Args>
auto emplace_value(Map& map, Key&& key, Args&&... args) {
return map.emplace(std::piecewise_construct,
std::forward_as_tuple(std::forward<Key>(key)),
std::forward_as_tuple(std::forward<Args>(args)...));
}
Which would let you write emplace_value(tmap, 10, 10, 10)
, even for {unordered_,}multimap
.
It is not necessary since for multimap case since there is no unique key, try_emplace
would never fail. The rational for adding try_emplace
to map was all the error prone code needed to deal with the case that key already exists, see the proposal n4279 (emphasis mine):
The existing interface of unique-keyed map containers (std::map, std::unordered_map) is slightly underspecified, which makes certain container mutations more complicated to write and error-prone than necessary. This paper describes new member function templates to fill this gap.
The justification and rationale for the new interface are given in N3873. The initial reaction to N3873 in Issaquah was that the existing map interfaces should be fixed rather than adding new interfaces. We explored this idea in N4006 in Rapperswil and decided that the original proposal was preferable (with some name changes). This paper only summarises the proposed extension without repeating the original discussion. We only restate the motivating code snippet here for motivation:
std::map<std::string, std::unique_ptr<Foo>> m; m["foo"] = nullptr; auto ptr = std::make_unique_ptr<Foo>; auto res = m.emplace("foo", std::move(ptr)); assert(ptr); // ??? (may or may not fire)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With