我正在选择两种将事物放入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);
我做了一些实验,看看哪一个会更好地发现插入独特元素时,行为(如效率)基本相同.
但是,在插入重复项的情况下,并且认为Value或DifferentValue的构造并不是微不足道的,我很惊讶地发现,无论是否插入对象,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创建一个后来忽略的对象有一个很好的理由?也就是说,它应该首先检查是否需要创建对象,如果它已经存在则提前出现?
(请注意,对于我的特定情况,默认初始化项目不被视为有效,因此问题实际上只是关于安抚)
为了记录,我在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.
我认为这将允许不创建对象.
最佳答案 在我看来,标准中引用的部分是误导性的,因为它表明,只有在容器中没有匹配元素时才构造对象.我猜他们试图说明:
Effects: Constructs a
value_type
objectt
withstd::forward<Args>(args)...
. Inserts the constructed objectt
if and only if there is no such element in the container with key equivalent to the key oft
.
原因是:函数emplace的实现必须构造t以便找出具有等效键的元素是否存在,因为实现必须调用散列函数和等于谓词.但是,通常只能使用value_type类型的对象调用它们,而不能使用用于构造这些对象的元组.
从理论上讲,可以指定一个emplace函数,如果已经存在具有等效键的元素,则不会构造t.有趣的是,类似的东西将添加到C 14 for std :: map :: find.请参阅以下文档:
> http://en.cppreference.com/w/cpp/container/map/find
有两个重载,可以与任意类型一起使用,只要比较功能满足一些额外的要求即可.有趣的是,std :: unordered_map没有这样的重载.