I was in the process of selecting one of two methods of putting things into an unordered_map:
std::unordered_map<Key, Value> map;
map.emplace(
std::piecewise_construct,
std::forward_as_tuple(a),
std::forward_as_tuple(b, c, d));
vs
std::unordered_map<Key, DifferentValue> map;
auto& value = map[a];
if (value.isDefaultInitialized())
value = DifferentValue(b, c, d);
I did some experiments to see which one would perform better to find that when inserting unique elements, the behaviour (as in efficiency) was basically equivalent.
However, in the case of inserting duplicate items, and consider that the construction of Value or DifferentValue is not trivial, I was surprised to find is that emplace constructs the object regardless of whether it will insert it or not.
So, the second method seems to win by far in that case since the default constructor just has isDefaultInitialized_(true) in there and not much more.
For emplace, the code seems to be:
... _M_emplace(std::true_type, _Args&&... __args) {
__node_type* __node = _M_allocate_node(std::forward<_Args>(__args)...);
const key_type& __k = this->_M_extract()(__node->_M_v);
...
if (__node_type* __p = _M_find_node(__bkt, __k, __code)) {
_M_deallocate_node(__node);
return std::make_pair(iterator(__p), false);
}
return std::make_pair(_M_insert_unique_node(__bkt, __code, __node), true);
}
So, although I'm going to go with the second method (even if it requires move assignment and move constructors and extra fields), I was wondering is there a good rationale for why emplace creates an object that it later disregards? That is, should it first check if it needs to create the object and early out if it already exists?
(note that for my particular case default initialized items are not considered valid, so the question is really just about emplace)
For the record, I found something under 23.2.4 table 102:
Effects: Inserts a value_type object t constructed with std::forward<Args>(args)...
if and only if there is no element in the container with key equivalent to the
key of t.
which I think would allow for not creating the object.