web-dev-qa-db-ja.com

ベクトルをベクトルに追加する最良の方法

std::vector<int> a;
std::vector<int> b;
std::vector<int> c;

bの要素とcの要素をaに追加して、これら3つのベクトルを連結したいと思います。これを行う最良の方法はどれですか、なぜですか?


1)vector::insertを使用して:

a.reserve(a.size() + b.size() + c.size());
a.insert(a.end(), b.begin(), b.end());
a.insert(a.end(), c.begin(), c.end());
b.clear();
c.clear();

2)std::copyを使用して:

a.reserve(a.size() + b.size() + c.size());
std::copy(b.begin(), b.end(), std::inserter(a, a.end()));
std::copy(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();

std::moveを使用して(C++11から):

a.reserve(a.size() + b.size() + c.size());
std::move(b.begin(), b.end(), std::inserter(a, a.end()));
std::move(c.begin(), c.end(), std::inserter(a, a.end()));
b.clear();
c.clear();
43
vdenotaris

私の意見では、最初の解決策が最善の方法です。

vector<>::insertは要素を追加するように設計されているため、最も適切なソリューションです。

宛先ベクトルでreserveを呼び出してスペースを確保できますが、多くのベクトルを一緒に追加しない限り、多くの利点が得られない可能性があります。vector<>::insertは、追加される要素の数を知っています。 1つのreserve呼び出しのみを避けます。

:これらがvectorのより複雑なタイプ(つまり、カスタムクラス、またはstd::string)である場合、std::moveを使用すると、ニースが得られますコピーコンストラクターが回避されるため、パフォーマンスが向上します。ただし、intのベクトルの場合、利点はありません。

注2std::moveを使用すると、ソースvectorのコンテンツが使用できなくなることに注意してください。

24
Xaqq

移動せずにコピーしたい場合、これが最善の方法です。

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),b.begin(),b.end());
a.insert(a.end(),c.begin(),c.end());

移動したい場合:

a.reserve(a.size()+b.size()+c.size()); // Reserve space first
a.insert(a.end(),std::make_move_iterator(b.begin()),
         std::make_move_iterator(b.end()));
a.insert(a.end(),std::make_move_iterator(c.begin()),
         std::make_move_iterator(c.end()));
b.swap(std::vector<int>()); // Clear and deallocate space
c.swap(std::vector<int>()); // Clear and deallocate space

更新:質問を数回編集して、ターゲットを移動させました。最初のオプションは、私の最初の提案と非常によく似ています。

更新2:C++ 11の時点で、 "空のベクターでスワップ"トリックを使用する必要がなくなる場合があります。ライブラリのvectorの実装に応じて、スペースをクリアおよび割り当て解除します。以下は、より直感的な方法で仕事をするかもしれません:

// Empty the vectors of objects
b.clear(); 
c.clear();

// Deallocate the memory allocated by the vectors 
// Note: Unlike the swap trick, this is non-binding and any space reduction
//       depends on the implementation of std::vector
b.shrink_to_fit();
c.shrink_to_fit();
19

insertは、追加する要素の数を把握し、コピーを開始する前に適合するようにベクトルのサイズを変更できるため、最初の選択肢が最適です。他の人はその情報を持っていないので、コピー後にサイズ変更を行う可能性があります。これは、最初のサイズ変更や複数回のサイズ変更よりも遅くなります。

ただし、@ michaelgoldshteynが示唆するように、2つの挿入を行うため、最終サイズで配列を自分でサイズ変更して、1つのサイズ変更を保存することもできます。

1
Pete Becker

bcのデータをベクトルaに本当に追加したい場合は、挿入を行う必要があります(実際には1。 ):

a.reserve( a.size() + b.size() + c.size() ); // preallocate memory (see why)
a.insert( a.end(), b.begin(), b.end() );
a.insert( a.end(), c.begin(), c.end() );

コンパイラーに応じてstd::copy(あなたの2。)は通常、高速であるはずです。

std::vectorは常にメモリ内で連続している必要があります。move(C++ 11で定義)および終了サイズがわかっている場合は、 ベクターを予約する必要があります(ベクターの不要な再割り当てを回避します)。ただし、パフォーマンスが本当に心配な場合は、3つのstd::vectorそして、あなたが彼らのデータを読まなければならないとき、それらを繰り返します。

0
Kyle_the_hacker