c – std :: unordered_map :: emplace对象创建

我正在选择两种将事物放入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 object t with std::forward<Args>(args).... Inserts the constructed object t if and only if there is no such element in the container with key equivalent to the key of t.

原因是:函数emplace的实现必须构造t以便找出具有等效键的元素是否存在,因为实现必须调用散列函数和等于谓词.但是,通常只能使用value_type类型的对象调用它们,而不能使用用于构造这些对象的元组.

从理论上讲,可以指定一个emplace函数,如果已经存在具有等效键的元素,则不会构造t.有趣的是,类似的东西将添加到C 14 for std :: map :: find.请参阅以下文档:

> http://en.cppreference.com/w/cpp/container/map/find

有两个重载,可以与任意类型一起使用,只要比较功能满足一些额外的要求即可.有趣的是,std :: unordered_map没有这样的重载.

点赞