web-dev-qa-db-ja.com

範囲をベクトルに移動する標準的な方法はありますか?

要素の範囲をベクトルに挿入する次のプログラムを考えてみます。

vector<string> v1;
vector<string> v2;

v1.Push_back("one");
v1.Push_back("two");
v1.Push_back("three");

v2.Push_back("four");
v2.Push_back("five");
v2.Push_back("six");

v1.insert(v1.end(), v2.begin(), v2.end());

これにより範囲が効率的にコピーされ、最大1つのサイズ変更が必要になるように、範囲全体に十分なスペースがターゲットベクトルに割り当てられます。次に、範囲をベクトルに移動しようとする次のプログラムを考えてみます。

vector<string> v1;
vector<string> v2;

v1.Push_back("one");
v1.Push_back("two");
v1.Push_back("three");

v2.Push_back("four");
v2.Push_back("five");
v2.Push_back("six");

for_each ( v2.begin(), v2.end(), [&v1]( string & s )
{
    v1.emplace_back(std::move(s));
});

これは正常に移動しますが、ターゲットベクトルにスペースを事前に割り当てることに関してinsert()が持つ利点を享受していないため、操作中にベクターのサイズが数回変更される可能性があります。

だから私の質問は、範囲をベクトルに移動できる挿入同等物はありますか?

55
Benj

insertとともにmove_iteratorを使用します:

v1.insert(v1.end(), make_move_iterator(v2.begin()), make_move_iterator(v2.end()));

24.5.3の例は、ほぼこれです。

(a)vector::insertがイテレータタグディスパッチを使用してランダムアクセスイテレータを検出し、サイズを事前計算する場合(コピーする例で想定している)、および( b)move_iteratorは、ラップするイテレータのイテレータカテゴリを保持します(これは標準で必要です)。

あいまいな点について:vector::insertがソースから移動できると確信しています(ソースは移動先と同じタイプなので、移動はコピー/移動と同じなので、ここでは無関係です)。しかし、他の点では同じ例に関連します)。必要なステートメントはまだ見つかりません。イテレータペアi,jinsertに渡された要件はT*iからEmplaceConstructibleになります。

81
Steve Jessop
  1. std::move 事前割り当てのアルゴリズム:

    #include <iterator>
    #include <algorithm>
    
    v1.reserve(v1.size() + v2.size()); // optional
    std::move(v2.begin(), v2.end(), std::back_inserter(v1));
    
  2. 以下はまだより柔軟です:

    v1.insert(v1.end(), 
         std::make_move_iterator(v2.begin()), 
         std::make_move_iterator(v2.end()));
    

    スティーブ・ジェソップは、それが何をするか、そしておそらくどのようにそれを行うかについての背景情報を提供しました。

33
sehe