1

一時オブジェクトの作成 (挿入されるオブジェクトのコンストラクター/デストラクタの呼び出し) を回避するために、項目をコンテナーに追加するときにemplace優先するC++11 の本の 1 つからの推奨事項を読んでいます。insertしかし、オブジェクトをマップに追加する方法がいくつかあるため、少し混乱しています。

#include <iostream>
#include <string>
#include <cstdint>
#include <map>

int main()
{
    std::string one     { "one" };
    std::string two     { "two" };

    std::map<uint32_t, std::string> testMap;

    testMap.insert(std::make_pair(1, one));         // 1
    testMap.emplace(2, two);                        // 2
    testMap.insert(std::make_pair(3, "three"));     // 3
    testMap.emplace(4, "four");                     // 4

    using valType = std::map < uint32_t, std::string >::value_type;
    testMap.emplace(valType(5, "five"));            // 5
    testMap.insert(valType(6, "six"));              // 6

    return 0;
}

そのようなコードを読んだときにすぐには見えない内部メカニズムもいくつか含まれています-完全な転送、暗黙的な変換...

マップ コンテナにアイテムを追加する最適な方法は何ですか?

4

1 に答える 1

1

選択肢を 1 つずつ考えてみましょう (さらに、言及されていない 1 つまたは 2 つの選択肢もあります)。

オプション 1 と 6 は、セマンティクスに関する限り、本質的に同じです。usingと は、pairの value_type を綴る 2 つの異なる方法ですmap。必要に応じて、ステートメントのtypedef代わりに aを使用して 3 番目の方法を追加できます。using

typedef std::map<uint32_t, std::string>::value_type valType;

...そして #6 に相当する C++98/03 を持っています。pairただし、3 つすべてが同じことを行うことになります。タイプの一時オブジェクトを作成し、それをmap.

バージョン 3 と 5 はほとんど同じです。彼らは を使用emplaceしますが、渡すものはすでにmapの value_type のオブジェクトです。それemplace自体が実行を開始するまでに、マップに格納されるオブジェクトのタイプはすでに構築されています。繰り返しますが、この 2 つの唯一の違いは、そのpair型を指定するために使用される構文にあります。また、typedef上で示したようなものを使用すると、現在using声明。バージョン 3 の使用insertとバージョン 5 の使用emplaceに実質的な違いはほとんどありません。いずれかのメンバー関数が呼び出されるまでに、既に一時オブジェクトを作成して渡しています。

オプション 2 と 4 はどちらも、実際emplaceにはおそらく意図されたように、個々のコンポーネントを渡し、それらをコンストラクターに完全に転送し、value_typeオブジェクトをその場で構築するため、一時的なオブジェクトを作成することを避けています。この 2 つの主な (唯一の?) 違いはstring、value_type のコンポーネントに渡すものが文字列リテラル (そこから一時std::stringオブジェクトを作成する必要がある) か、std::string事前に作成されたオブジェクトかという点です。

それらの間の選択は自明ではないかもしれません。(上記のように)一度だけ実行する場合、実際にはまったく違いはありません-いつ作成するかに関係なく文字列オブジェクトを作成し、それをmap.

したがって、実際の違いを生むには、文字列オブジェクトを事前に作成してから、同じ文字列オブジェクトを繰り返し挿入する必要がありますmap。それ自体は非常に珍しいことです。ほとんどの場合、外部データを文字列に読み取り、それをmap. 実際に同じ文字列リテラルを繰り返し挿入 (から構築) する場合、合理的なコンパイラが結果の文字列がループ不変であることを検出し、構造をループから引き上げて、本質的に同じ効果を与えるstd::string可能性はかなり高いです。string

結論:mapそれ自体の使用に関しては、選択肢 2 と 4 は同等です。これら 2 つの間では、オプション 4 よりもオプション 2 を使用する (つまり、文字列を事前に作成する) という実際の努力はしませんが、ほとんどの場合、それは起こる可能性があります。単に単一の文字列リテラルをマップに挿入することはめったに役に立ちません。マップに配置する文字列は、外部データ ソースから頻繁に取得されるstringため、(たとえば)std::getlineファイルからデータを読み取ったときに得られたものであるため、.

于 2015-01-21T17:01:41.407 に答える