1つのベクトルを別のベクトルにコピーする高速な方法


155

私は2つの方法を好む:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

どうやってやるの?


14
2つ目は誤解を招く名前です-コピーではないため(高速ですが)。
匿名

回答:


126

引数を参照で送信する場合、2番目の例は機能しません。もしかして

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

それはうまくいきますが、より簡単な方法は

vector<int> new_(original);

いいですね。しかし、それはベクトルの配列に対しては機能しません。例えば:vector <int> A [n];
ABcDexter 14

8
それはコピーではなくスワップです。
sdd '28年

1
@sdd-いいえ、そうではありません。引数リストを確認してください。original関数の引数のコピーです。
rlbond

249

彼らは同じではないけどね?1つはコピーで、もう1つはスワップです。したがって、関数名です。

私のお気に入りは:

a = b;

ベクトルabはどこですか。


3
実際、アプローチは値渡しであり、コンパイラーはコピーコンストラクターを呼び出して、新しく作成された要素を交換します。そのため、rlbondは、コピーコンストラクターを直接呼び出して同じ効果を実現することを推奨しています。
デビッドロドリゲス-ドリベス2009年

1
ただし、オリジナルをvalとして渡す関数がないと、rlbonを呼び出すことはできません。それ以外の場合は、元のものが空になります。2番目のソリューションでは、常に値で呼び出すため、元のベクトルの日付が失われることはありません。(スワップがポインターを扱うと仮定)
Eyad Ebrahim 2013

bの要素をaに移動しませんか(bのサイズ== 0のままにします)?
ジョナサン。

1
@ジョナサン。あなたがa = bそれについて話していると仮定すると、いいえ。割り当ての意味:変更せずにa等しくbするb。これとは対照的に、std::swap(a, b)その内容を交換します(そうbさんはsize今何だろうa前にしていたS ')。おそらく移動操作を考えています(C ++ 11で発生しますが、このような通常の割り当てでは発生しません)。このような動きは残してb見る- 、エヘン、「面白い」状態にstackoverflow.com/questions/17730689/...を
ダニエルエリカー

1
@ジョナサン。2つのアンパサンドに注意してください&&。そのバージョンは右辺値参照にのみ使用されます。(b上記の例のように)非const値とは一致しません。さらに複雑にするには、「en.cppreference.com/w/cpp/language/value_categoryを参照bしてa = std::move(b);ください」と言うことで1つに変えることができます。
Daniel Earwicker 2014年

74

これは、ベクターのコピーを作成する別の有効な方法です。コンストラクターを使用するだけです。

std::vector<int> newvector(oldvector);

これはstd::copy、ベクトル全体を最初から最後までstd::back_insert新しいベクトルに移動するのに使用するよりもさらに簡単です。

そうは言っても、あなたの.swap()1つはコピーではなく、2つのベクトルを交換します。オリジナルを変更して、もう何も含まないようにします!これはコピーではありません。


19

直接的な答え:

  • =演算子を使用する

std::vector::operator=コンテナーのパブリックメンバー関数を使用してstd::vector、ベクトルから別のベクトルに値を割り当てることができます。

  • コンストラクター関数を使用する

さらに、コンストラクター関数も意味があります。パラメーターとして別のベクトルを使用するコンストラクター関数(例x:)は、の各要素のコピーを使用xして同じ順序でコンテナーを構築します。

注意:

  • 使ってはいけません std::vector::swap

std::vector::swapはベクターを別のベクターにコピーするのではなく、その名前が示すように、実際には2つのベクターの要素を交換しています。言い換えると、コピー元のソースベクトルstd::vector::swapはが呼び出された後に変更されますが、これはおそらく予期したものではありません。

  • 深いまたは浅いコピー?

ソースベクトルの要素が他のデータへのポインターである場合、深いコピーが必要になることがあります。

ウィキペディアによると:

ディープコピー、つまりフィールドが逆参照されることを意味します。コピーされるオブジェクトへの参照ではなく、参照されるオブジェクトに対して新しいコピーオブジェクトが作成され、Bに配置されたオブジェクトへの参照が作成されます。

実際、現在C ++には、ディープコピーを行う組み込みの方法はありません。上記のすべての方法は浅いです。深いコピーが必要な場合は、ベクターをトラバースして、参照のコピーを手動で作成できます。代わりに、反復のために反復子を検討できます。イテレータについての議論はこの質問を超えています。

参考文献

std::vectorcplusplus.com のページ


14

スワップを使用してベクターをコピーしないでください。「元の」ベクターが変更されます。

代わりに、元のパラメーターを新しいパラメーターに渡します。


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

ベクターがすでに存在していて、単にコピーしたい場合は、次のようにします。

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
memcpyしないでください。また、memcpyはサイズをバイト単位で取得するため、これは機能しません。また、他のベクトルがすでに存在する場合newVec = oldVecは、他の答えの1つと同じように実行できます。
FDinoff

はい、そうです。見なかった。@FDinoff、以下の1つは機能しますが、なぜmemcpyを使用しないことをお勧めしますか?newVec = oldVecよりもはるかに速いようです。memcpy(&newVec.at(0)、&oldVec.at(0)、oldVec.size()* sizeof(int));
sgowd 2015

1
一般的なケースでは、コピーコンストラクターを呼び出さずにオブジェクトをコピーすると、微妙なバグが発生する可能性があります。この場合、私は彼らが同じパフォーマンスを持っていたと思いました。そうでない場合、ベクターは既にパフォーマンス最適化されていないため、ベクターはパフォーマンス最適化されていなかったと言えます。実際にベンチマークを書きましたか?
FDinoff

私はあなたを批判していませんでした。私のチームリーダーも同じことを提案し、理解しようとしました。
sgowd 2015年

(あなたが私を批判しているとは思わなかった。)まだあなたが理解できないことはありますか?
FDinoff、2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.