V1をターゲットベクトルとし、v2をその後ろに追加する必要があります。
私は今やっています:
v1.reserve(v1.size() + v2.size());
copy(v2.begin(), v2.end(), back_inserter(v1));
これが最も効率的な方法ですか?または、メモリのチャンクをコピーするだけで実行できますか?ありがとう!
多くの議論(およびMatthieu M.とvillintehaspamからの合理的なコメント)の後、提案を次のように変更します。
v1.insert( v1.end(), v2.begin(), v2.end() );
以前の提案をここに保管します。
v1.reserve( v1.size() + v2.size() );
v1.insert( v1.end(), v2.begin(), v2.end() );
後者の方法で行う理由はいくつかありますが、どれも十分な強度はありません。
reserve
についてもそのような保証はありませんが、特定の実装ではそれは真実かもしれません。ボトルネックを探す場合は、それを確認するのが妥当かもしれません。reserve
を使用すると、単一の再割り当てのみが行われることをC++標準で保証しますが、insert
は非効率的に実装され、複数の再割り当てを行います(特定の実装でテストすることもできます)。おそらく、専用のメソッドを使用する方がより簡単で簡単です: vector.insert
v1.insert(v1.end(), v2.begin(), v2.end());
Michaelが言及しているように、反復子が入力反復子でない限り、ベクターは必要なサイズを計算し、追加されたデータを線形複雑度で一度にコピーします。
次のコードを使用して簡単にパフォーマンスを測定し、
v1.insert( v1.end(), v2.begin(), v2.end() );
(すでに述べたように)正しい選択のようです。それでも、報告されたパフォーマンスは以下のとおりです。
テストコード:
#include <vector>
#include <string>
#include <boost/timer/timer.hpp>
//==============================================================================
//
//==============================================================================
/// Returns a vector containing the sequence [ 0, ... , n-1 ].
inline std::vector<int> _range(const int n)
{
std::vector<int> tmp(n);
for(int i=0; i<n; i++)
tmp[i] = i;
return tmp;
}
void test_perf_vector_append()
{
const vector<int> testdata1 = _range(100000000);
const vector<int> testdata2 = _range(100000000);
vector<int> testdata;
printf("--------------------------------------------------------------\n");
printf(" METHOD: Push_back()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
for(size_t i=0; i<testdata2.size(); i++)
{
testdata.Push_back(testdata2[i]);
}
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + Push_back()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
for(size_t i=0; i<testdata2.size(); i++)
{
testdata.Push_back(testdata2[i]);
}
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: insert()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.insert( testdata.end(), testdata2.begin(), testdata2.end() );
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + insert()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve( testdata.size() + testdata.size() );
testdata.insert( testdata.end(), testdata2.begin(), testdata2.end() );
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: copy() + back_inserter()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
copy(testdata2.begin(), testdata2.end(), back_inserter(testdata));
}
printf("--------------------------------------------------------------\n");
printf(" METHOD: reserve() + copy() + back_inserter()\n");
printf("--------------------------------------------------------------\n");
testdata.clear();
{ vector<int>().swap(testdata); }
testdata = testdata1;
{
boost::timer::auto_cpu_timer t;
testdata.reserve(testdata.size() + testdata2.size());
copy(testdata2.begin(), testdata2.end(), back_inserter(testdata));
}
}
Visual Studio 2008 SP1、x64、リリースモード、/ O2/LTCGでは、出力は次のようになります。
--------------------------------------------------------------
METHOD: Push_back()
--------------------------------------------------------------
0.933077s wall, 0.577204s user + 0.343202s system = 0.920406s CPU (98.6%)
--------------------------------------------------------------
METHOD: reserve() + Push_back()
--------------------------------------------------------------
0.612753s wall, 0.452403s user + 0.171601s system = 0.624004s CPU (101.8%)
--------------------------------------------------------------
METHOD: insert()
--------------------------------------------------------------
0.424065s wall, 0.280802s user + 0.140401s system = 0.421203s CPU (99.3%)
--------------------------------------------------------------
METHOD: reserve() + insert()
--------------------------------------------------------------
0.637081s wall, 0.421203s user + 0.218401s system = 0.639604s CPU (100.4%)
--------------------------------------------------------------
METHOD: copy() + back_inserter()
--------------------------------------------------------------
0.743658s wall, 0.639604s user + 0.109201s system = 0.748805s CPU (100.7%)
--------------------------------------------------------------
METHOD: reserve() + copy() + back_inserter()
--------------------------------------------------------------
0.748560s wall, 0.624004s user + 0.124801s system = 0.748805s CPU (100.0%)
Boostを使用する場合は、RangeExライブラリの開発バージョンをダウンロードできます Boost Vaultから 。このライブラリ。しばらく前にBoostに受け入れられましたが、今のところメインディストリビューションと統合されていません。その中に、あなたが望むものを正確に実行する新しい範囲ベースのアルゴリズムがあります:
boost::Push_back(v1, v2);
内部的には、UncleBensの答えのように機能しますが、コードはより簡潔で読みやすいです。
ポッドタイプのベクターがあり、本当にパフォーマンスが必要な場合は、memcpyを使用できます。これはvector <>。insert(...)よりも高速である必要があります。
v2.resize(v1.size() + v2.size());
memcpy((void*)&v1.front(), (void*)&v2[v1.size()], sizeof(v1.front())*v1.size());
更新:パフォーマンスが本当に必要な場合にのみこれを使用しますが、reallyが必要です。コードisはポッドタイプに対して安全です。