6

unordered_map に物を入れる 2 つの方法のいずれかを選択する過程にありました。

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 または DifferentValue の構築は自明ではないことを考えると、emplace がオブジェクトを挿入するかどうかに関係なくオブジェクトを構築することに驚きました。

そのため、デフォルトのコンストラクターには isDefaultInitialized_(true) が含まれているだけで、それ以上のものはないため、2 番目の方法が圧倒的に勝つようです。

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);
}

したがって、私は 2 番目の方法を使用しますが (移動代入と移動コンストラクターと追加のフィールドが必要な場合でも)、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.

オブジェクトを作成しないことを許可すると思います。

4

2 に答える 2