web-dev-qa-db-ja.com

C ++:value_typeとmake_pairのどちらがマップ挿入の方が速いですか?

_typedef map<KeyType, ValType> KVMap;
KVMap kvmap;

kvmap.insert( KVMap::value_type( key, val ) );
kvmap.insert( make_pair( key, val ) );
_

STLマップに挿入する上記のオプションのどれが常に速いですか?どうして?

注:insert()は、キーと値のペアをマップに追加する(更新しない)ために_[]=_を使用するよりも高速であることをよく知っています。私のクエリは更新ではなく追加に関するものであると想定してください。したがって、私はそれをinsert()に制限しました。

23
Ashwin Nanjappa

このため、最初は'epsilon-faster'になる可能性があります(標準の23.3.1から):

typedef pair<const Key, T> value_type;

[...]

pair<iterator, bool> insert(const value_type& x);
  • 最初のバージョンでは、std::map<K,V>::insertが期待する適切なタイプを直接作成します。

  • 2番目のバージョンでは、std::pairテンプレートコンストラクターを使用した変換が含まれます。実際、std::make_pairはテンプレート引数をKeyTypeValTypeに推測する可能性が高いため、std::pair<KeyType, ValType>を返します。

    これは、std::map<K,V>::insertのパラメータタイプであるstd::pair<const KeyType, ValType>とは一致しません(違いはconstで修飾されています)。 std::pair変換コンストラクターは、std::pair<const K, V>からstd::pair<K, V>を作成するために使用されます。

公平を期すために、違いを測定することすらできないと思います(そして、人気のあるコンパイラーが実際にこれらに対して異なるコードを生成するかどうかさえわかりません)。

20
icecrime

実際には、value_typeよりもmake_pairに対して行われるべき議論があります。これは、さまざまな不可解な理由により、make_pairが引数を値で受け入れるためです。一方、value_typeのエイリアスであるstd::pair<const Key, value>には、const参照によって渡された引数を使用してコンストラクターが呼び出されます。 make_pairの値渡しと参照渡しの比較では、効率が低下する可能性があります。これは、理論的にはプログラムに顕著な影響を与える可能性があります。

make_pairで心配すべきもう1つの問題は、make_pairは通常、map内に必要なstd::pair<Key, Value>に対してタイプstd::pair<const Key, Value>のペアを作成することです。これは、変換を正しく機能させるために、今度はpairの別の不要なコピーが作成されている可能性があることを意味します。

つまり、make_pairを使用すると、キーと値の2つの完全に不要なコピーが作成される可能性がありますが、value_typeコンストラクターを使用するとコピーが作成されません。

12
templatetypedef

これは単なる補足です。

insert( make_pair(...) )は、他の回答者が言及した理由により、概念的にコピーコンストラクターを4回呼び出します。

insert( value_type(...) )はコピーコンストラクターを2回呼び出します。

_operator[]_は、通常の実装では、デフォルトのコンストラクターを1回呼び出し、コンストラクターを2回コピーします。デフォルトのコンストラクターは、insert( value_type( ..., mapped_type() ) )の_operator[]_内で呼び出されます。コピーコンストラクタは、insert()の引数(pair)をコピーするために1回呼び出され、マップの内部ノードをコピー構築するために1回呼び出されます。

したがって、insertを_make_pair_と一緒に使用する場合、追加してもinsertが常に_operator[]_よりも速いとは言えません。おそらく、状況によるでしょう。ご存知かもしれませんが、上記を考慮して、emplaceが新しい標準として提案されました。

4
Ise Wisteria

それらは基本的に同じものです。 _KVMap::value_type_は_std::pair<KeyType, ValType>_のtypedefであるため、コンストラクターを呼び出すだけです。 _std::make_pair_は、コンストラクターを呼び出すだけのテンプレート関数です(テンプレートタイプは無料の関数では推定できますが、コンストラクターでは推定できないために存在します)。信じられないほど標準的な最適化がすべて行われると、違いが生じる理由はありません。

あなたがどのようにテストしているのかわかりませんが、それを間違って行う方法はたくさんあります。

insert()と_operator[]_を介した割り当てについては、後者は概念的にさらに多くの作業を行う必要があります(この方法で新しい要素を追加すると、最初にデフォルトで要素を作成し、次にその上に割り当てます)が、ValTypeによっては、基本的に同じものに再び最適化される可能性があります。

2
Karl Knechtel