2017-08-03 8 views
1
#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    int a; 
    int b; 
}; 

int main() 
{ 
    map<int, FooStruct> fooMap; 
    fooMap.emplace<int, FooStruct>(0, {1, 2}); 
    return 0; 
} 

一時的なコピーを防止するという点では、上記のemplaceの正しい使い方ですか?上記のフォームはemplaceを使ってstd :: mapに追加するときの一時的なコピーを避けるには?

fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2})); 

またはこれらのフォームが等価であるよりも優れているし、それらの両方がFooStructの一時コピーを作成しないように?

+0

違いは、 'make_pair'は' pair'の移動コンストラクタのセマンティクスを使いますが、他の方法ではテンプレートのコンストラクタを呼び出すことができます。 – Swift

+0

'fooMap.emplace(std :: piecewise_construct、std :: forward_as_tuple(0)、std :: forward_as_tuple(1、2));'はどうでしょうか? – max66

+0

@ max66:あなたのフォームは上記の2つより優れていると言っていますか?もしそうなら、なぜそれが事実であるか説明してもらえますか? – DigitalEye

答えて

0

EDIT:このスレッドで説明した3つの形態の

、不要なコピーを回避する一つの@ max66によって提案された形態です。次のコードは、その出力は、アクションでこれらの3つの形式が捉え

#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    FooStruct() 
    { 
     cout << "FooStruct Default Constructor" << endl; 
    } 
    FooStruct(const FooStruct& other) 
    { 
     this->a = other.a; 
     this->b = other.b; 
     cout << "FooStruct Copy Constructor" << endl; 
    } 
    FooStruct(int a, int b) 
    { 
     this->a = a; 
     this->b = b; 
     cout << "FooStruct Parametrized Constructor" << endl; 
    } 
    int a; 
    int b; 
}; 

出力:

foo.emplace<int, FooStruct>(0, {1, 2}) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 })) 
FooStruct Parametrized Constructor 
FooStruct Copy Constructor 
FooStruct Copy Constructor 
fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4)) 
FooStruct Parametrized Constructor 

============

ORIGINAL(WRONG)

私は少し怠惰で、質問を投稿する前に深く掘り下げようとはしませんでした。私は今これらの3つのフォーム(@ max66のコメントから3番目のフォームが来ている)が、FooStructという一時的なコピーの作成を避けるという点で同等であることを確認しました。

#include <iostream> 
#include <map> 
using namespace std; 

struct FooStruct 
{ 
    FooStruct() { cout << "FooStruct Default Constructor" << endl; } 
    FooStruct(int a, int b) { this->a = a; this->b = b; cout << "FooStruct Parametrized Constructor" << endl; } 
    int a; 
    int b; 
}; 

int main() 
{ 
    map<int, FooStruct> fooMap; 
    fooMap.emplace<int, FooStruct>(0, {1, 2}); 
    fooMap.emplace(make_pair<int, FooStruct>(1, { 2, 3 })); 
    fooMap.emplace(std::piecewise_construct, std::forward_as_tuple(2), std::forward_as_tuple(2, 4)); 
    return 0; 
} 

(ビジュアルC++ 2015で構築された)上記のコードは次のような出力生成:

FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 
FooStruct Parametrized Constructor 

PSを:私は上記の出力の各行は

上記単一据え付けるコールに対応していることを確認しました
+1

私は、「これらの3つのフォームはすべて、FooStructの一時的なコピーの作成を避けるという点で同等です。これは第1および第3の形式で当てはまります。 2番目のフォームのケースでは、わかっているように、コピーコンストラクタ(Cから始まる移動コンストラクタ)を使ってマップ内にペアを構築するために使用される 'int' /' FooStruct'ペアの一時コピーの作成があります++ 11)。 – max66

+0

@ max66:あなたは正しいです。私はコピーコンストラクタを忘れてしまい、明らかに間違った結論に達しました。ですから、forward_as_tupleが最良の解決策であるというあなたのフォームが分かりました。私はこの発見を反映するために私の答えを編集します。 – DigitalEye

1

あなたが簡潔として「正しさ」を定義した場合、あなたはこのようstd::map::insertの代わりstd::map::emplaceを使用することもできます。

fooMap.insert({0, {1, 2}}); 
(また、簡潔に欠けている)

fooMap.emplace(std::piecewise_construct, 
    std::forward_as_tuple(0), 
    std::forward_as_tuple(1, 2)); 

emplace

あなたが明示的にあなたの例のように種類を指定したりする@ max66によって提案された場合には、明示的にFooStructでコンストラクタを定義するかがあります。

fooMap.insert({0, {1, 2}});はまた、移動コンストラクタstd::pairのを@Swiftが指摘したように使用するように作成されるオブジェクトの量で

fooMap.emplace(make_pair<int, FooStruct>(0, {1, 2})); 

異なるべきではありません。

「正しい」とは「コンパイル可能であり、実行時に期待どおりに動作する」ことを意味する場合、両方の例が正しい。

+0

よろしくお願いいたします。私が実際にしていたのは、マップのメモリに直接構築されるFooStructの単一のインスタンスでした。 'fooMap.emplace(std :: piecewise_construct、std :: forward_as_tuple(0)、std :: forward_as_tuple(1,2));'これだけを達成します。簡潔であるかどうかにかかわらず、一時的なFooStructインスタンスの作成が必要になります。これは避けたいものです。 – DigitalEye

+0

最小限の量の物を探していたことを反映するために質問を更新してください。また、この形式の 'emplace'は、コンパイラがすべての違いを最適化でき、アセンブリを比較する必要があるため、実行時パフォーマンスのメリットがほとんどまたはまったくない場合があります。 –

関連する問題