我正在选择将事物放入 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));
对比
std::unordered_map<Key, DifferentValue> map;
auto& value = map[a];
if (value.isDefaultInitialized())
value = DifferentValue(b, c, d);
我做了一些实验,看看哪一个表现更好,发现在插入独特元素时,行为(如效率)基本上是等效的。
但是,在插入重复项的情况下,考虑到Value或DifferentialValue的构造并非易事,我惊讶地发现,无论插入与否,emplace都会构造对象。
因此,在这种情况下,第二种方法似乎到目前为止更胜一筹,因为默认构造函数中只有 isDefaultInitialized_(true) ,仅此而已。
对于 emplace,代码似乎是:
... _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);
}
所以,虽然我将使用第二种方法(即使它需要移动赋值和移动构造函数和额外的字段),我想知道为什么 emplace 创建一个后来忽略的对象有很好的理由吗?也就是说,它是否应该首先检查它是否需要创建对象,如果它已经存在则提前退出?
(请注意,对于我的特殊情况,默认初始化项不被认为是有效的,所以问题实际上只是关于 emplace)
作为记录,我在 23.2.4 表 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.
我认为这将允许不创建对象。