後で処理するために保存する必要がある、プログラムの別の部分から関数に渡される値の配列があります。データを処理する前に関数が何回呼び出されるかわからないため、動的ストレージ構造が必要なので、std::vector
. push_back
すべての値に対して個別に標準ループを実行する必要はありませんmemcpy
。
10 に答える
ここには多くの答えがあり、ほぼすべての答えが仕事を成し遂げます。
ただし、誤解を招くアドバイスがいくつかあります。
オプションは次のとおりです。
vector<int> dataVec;
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
// Method 1: Copy the array to the vector using back_inserter.
{
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 2: Same as 1 but pre-extend the vector by the size of the array using reserve
{
dataVec.reserve(dataVec.size() + dataArraySize);
copy(&dataArray[0], &dataArray[dataArraySize], back_inserter(dataVec));
}
// Method 3: Memcpy
{
dataVec.resize(dataVec.size() + dataArraySize);
memcpy(&dataVec[dataVec.size() - dataArraySize], &dataArray[0], dataArraySize * sizeof(int));
}
// Method 4: vector::insert
{
dataVec.insert(dataVec.end(), &dataArray[0], &dataArray[dataArraySize]);
}
// Method 5: vector + vector
{
vector<int> dataVec2(&dataArray[0], &dataArray[dataArraySize]);
dataVec.insert(dataVec.end(), dataVec2.begin(), dataVec2.end());
}
簡単に言うと、方法 4 は vector::insert を使用して、bsruth のシナリオに最適です。
ここにいくつかの悲惨な詳細があります:
方法 1がおそらく最も理解しやすいでしょう。配列から各要素をコピーして、ベクターの後ろにプッシュするだけです。悲しいかな、それは遅いです。ループがあるため (copy 関数で暗示されます)、各要素を個別に処理する必要があります。配列とベクトルが連続したブロックであることがわかっているという事実に基づいて、パフォーマンスを向上させることはできません。
方法 2は、方法 1 に対する推奨されるパフォーマンスの向上です。配列を追加する前に、配列のサイズを事前に予約してください。大規模な配列の場合、これが役立つ場合があります。ただし、ここでの最善のアドバイスは、プロファイリングで改善が得られる可能性があることが示唆されない限り (または、イテレータが無効にならないようにする必要がある場合)、reserve を使用しないことです。 Bjarne も同意します。ちなみに、この方法はほとんどの場合最も遅いことがわかりましたが、方法1よりも定期的に大幅に遅い理由を包括的に説明するのに苦労しています...
方法 3は昔ながらの解決策です。問題に C を投げてください。POD タイプでは問題なく高速に動作します。この場合、memcpy は vector の境界外で動作し、サイズが変更されたことを vector に伝える方法がないため、resize を呼び出す必要があります。醜い解決策 (バイトコピー!) であることに加えて、これはPOD タイプにのみ使用できることを覚えておいてください。私はこのソリューションを決して使用しません。
方法 4が最善の方法です。その意味は明確で、(通常) 最速であり、あらゆるオブジェクトに対して機能します。このアプリケーションでこの方法を使用することのマイナス面はありません。
方法 5は方法 4 を微調整したものです。配列をベクターにコピーしてから追加します。良いオプション - 一般的に高速で明確です。
最後に、配列の代わりにベクトルを使用できることをご存知でしょうか? 関数が C スタイルの配列を想定している場合でも、ベクトルを使用できます。
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
それが誰かを助けることを願っています!
配列と配列サイズを取得した後にベクトルを作成できる場合は、次のように言えます。
std::vector<ValueType> vec(a, a + n);
a
...あなたの配列でn
あり、それに含まれる要素の数であると仮定します。それ以外の場合は、std::copy()
w/resize()
でうまくいきます。
memcpy()
値がプレーン オールド データ (POD) 型であることを確認できない限り、私は近づきません。
また、これらのいずれも for ループを実際に回避していないことに注意してください。これは、コード内で for ループを表示する必要があるかどうかの問題です。値をコピーする場合、O(n) 実行時のパフォーマンスは避けられません。
最後に、C スタイルの配列は、ほとんどの STL アルゴリズムに対して完全に有効なコンテナーであることに注意してください。生のポインターは と同等begin()
であり、( ptr + n
) は と同等end()
です。
既存のデータを置き換えるだけの場合は、これを行うことができます
std::vector<int> data; // evil global :)
void CopyData(int *newData, size_t count)
{
data.assign(newData, newData + count);
}
std::copyが探しているものです。
自分の回答しか編集できないので、質問に対する他の回答から複合回答を作成します。回答してくださった皆様、ありがとうございました。
std::copyを使用すると、これは引き続きバックグラウンドで繰り返されますが、コードを入力する必要はありません。
int foo(int* data, int size)
{
static std::vector<int> my_data; //normally a class variable
std::copy(data, data + size, std::back_inserter(my_data));
return 0;
}
通常のmemcpyを使用します。これはおそらく基本的なデータ型 (つまり int) に最適ですが、構造体やクラスのより複雑な配列には適していません。
vector<int> x(size);
memcpy(&x[0], source, size*sizeof(int));
int dataArray[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//source
unsigned dataArraySize = sizeof(dataArray) / sizeof(int);
std::vector<int> myvector (dataArraySize );//target
std::copy ( myints, myints+dataArraySize , myvector.begin() );
//myvector now has 1,2,3,...10 :-)
さらに別の答えとして、その人が「関数が何回呼び出されるかわからない」と言ったので、次のようなベクトル挿入メソッドを使用して、値の配列をベクトルの最後に追加できます。
vector<int> x;
void AddValues(int* values, size_t size)
{
x.insert(x.end(), values, values+size);
}
ベクトルの実装は、イテレーターの型と型自体に基づいて値を挿入するための最良の方法を最適化できるはずなので、この方法が好きです。あなたはstlの実装についていくらか返信しています。
最速の速度を保証する必要があり、タイプがPODタイプであることがわかっている場合は、Thomasの回答のサイズ変更方法をお勧めします。
vector<int> x;
void AddValues(int* values, size_t size)
{
size_t old_size(x.size());
x.resize(old_size + size, 0);
memcpy(&x[old_size], values, size * sizeof(int));
}
memcpyを避けてください、と私は言います。本当に必要でない限り、ポインター操作をいじる理由はありません。また、POD 型 (int など) でのみ機能しますが、構築が必要な型を扱っている場合は失敗します。
上記のメソッドに加えて、std::Vector.reserve()、std::Vector.resize() のいずれかを使用するか、サイズに合わせてベクトルを構築して、ベクトルに十分な要素があることを確認する必要があります。それはあなたのデータを保持します。そうしないと、メモリが破損します。これは、std::copy() または memcpy() のいずれかに当てはまります。
これが vector.push_back() を使用する理由です。ベクトルの末尾を超えて書き込むことはできません。
ベクトル内のアイテムの大きさがわかっていると仮定します。
std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));