32

これに関する問題は、巨大なオブジェクトがマップにコピーされることです

Huge huge1(some,args);
Huge huge2(some,args);

std::map<int,Huge> map1;
std::map<Huge,int> map2;

map1.insert({0,huge1});
map2.insert({huge2,0});

どうすれば移動を保証できますか? これは機能しますか、それとも他にもありますか?

map1.insert({0,std::move(huge1)});
map2.insert({std::move(huge2),0});
4

4 に答える 4

16

あなたはそれをすることができます({0,std::move(huge1)}部分)。ただし、次のように仲介者をスキップすることもできます(関数内でオブジェクトを作成していると仮定します)。

map1.emplace(std::piecewise_construct, 0, std::forward_as_tuple(some, args));
map2.emplace(std::piecewise_construct, std::forward_as_tuple(some, args), 0);

または、関数にオブジェクトが指定されている場合でも、次を使用できますemplace

map1.emplace(0, std::move(huge1));
map2.emplace(std::move(huge1), 0);
于 2013-02-11T16:34:47.327 に答える
6

コピーと移動の両方を回避する別の方法は、を使用することstd::map::emplace()です。リンクされたリファレンスページから:

コンテナに新しい要素を挿入します。要素はインプレースで構築されます。つまり、コピーまたは移動操作は実行されません。要素型のコンストラクター(value_type、つまりstd :: pair)は、関数に提供されたものとまったく同じ引数で呼び出され、std :: forward(args)...で転送されます。

于 2013-02-11T16:35:39.520 に答える
2

上記に加えて、 のコピー コンストラクターの欠如を利用することもできますがstd::unique_ptr<>、これによりインターフェイスがわずかに変更されます。

#include <iostream>
#include <map>
#include <memory>

class Huge {
 public:
  Huge(int i) : x{i} {}
  int x;
};

using HugePtrT = std::unique_ptr<Huge>;
using MyMapT = std::map<int, HugePtrT>;


int
main() {
  MyMapT myMap;
  myMap[42].reset(new Huge{1});
  std::cout << myMap[42]->x << std::endl;
  myMap[43] = std::move(myMap[42]);
  if (myMap[42])
    std::cout << "42: " << myMap[42]->x << std::endl;
  if (myMap[43])
    std::cout << "43: " << myMap[43]->x << std::endl;
}

これにより、期待される出力が生成されます。

1
43: 1

呼び出しを省略するstd::move()と、プログラムはコンパイルに失敗します。同様に、 を使用.reset()してポインターを割り当てることができます。

これには、R 値コンストラクターを持たないクラスで機能し、非常に軽量であり、メモリの所有権が明確に定義されており、- のboost::optional<>ようなセマンティクスが得られるという利点があります。std::unique_ptrR 値の移動されたオブジェクトには割り当てが必要なため、R 値のコンストラクターを介して移動されたオブジェクトよりも軽量な引数を作成できます(公平を期すために、私が使用しているすべての C++11 コンパイラーは戻り値の最適化またはコピー省略のサポートに注意してください)、たとえオブジェクトの内部が移動されたとしても。

std::unique_ptr<>このように機能する理由std::unique_ptr<>は、コピー コンストラクターがなく、ムーブ コンストラクターしかないためです。

于 2013-02-19T09:34:51.770 に答える