web-dev-qa-db-ja.com

配列の内容をループせずにC ++のstd :: vectorにコピーするにはどうすればよいですか?

後で処理するために保存する必要があるプログラムの別の部分から関数に渡される値の配列があります。データを処理する前に関数が何回呼び出されるかわからないので、動的ストレージ構造が必要なので、std::vectorを選択しました。すべての値を個別にPush_backする標準ループを実行する必要はありません。memcpyに似たものを使用してすべてをコピーすることができればいいでしょう。

101
bsruth

配列と配列サイズを取得した後にベクトルを構築できる場合、次のように言うことができます。

std::vector<ValueType> vec(a, a + n);

... aは配列であり、nはそれに含まれる要素の数であると仮定します。そうでなければ、std::copy() w/resize()がトリックを行います。

値が従来のデータ(POD)型であることを確認できない限り、memcpy()には近づかないでしょう。

また、これらのどれもforループを実際に回避しないことに注意してください。これは、コード内でループを表示する必要があるかどうかの問題にすぎません。 O(n)ランタイムのパフォーマンスは、値をコピーするために避けられません。

最後に、Cスタイルの配列はほとんどのSTLアルゴリズムにとって完全に有効なコンテナです。生のポインタはbegin()と同等であり、(ptr + n)はend()と同等です。

99
Drew Hall

ここには多くの答えがあり、それらのほぼすべてが仕事を成し遂げます。

ただし、誤解を招くアドバイスがいくつかあります。

オプションは次のとおりです。

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は、おそらく最も理解しやすいでしょう。配列から各要素をコピーし、ベクターの後ろにプッシュするだけです。悲しいかな、遅いです。ループが存在するため(コピー機能で暗示される)、各要素は個別に処理する必要があります。配列とベクトルが連続したブロックであることがわかっているという事実に基づいて、パフォーマンスを改善することはできません。

方法2は、方法1に対して推奨されるパフォーマンスの改善です。追加する前に、配列のサイズを事前に予約するだけです。大きな配列の場合、このmightが役立ちます。ただし、ここでの最善のアドバイスは、プロファイリングで改善が得られる可能性がある(またはイテレーターが無効化されないようにする必要がある)場合を除き、リザーブを使用しないことです。 Bjarneは同意します 。ちなみに、この方法はほとんどの場合slowestを実行することがわかりましたが、なぜそれが定期的に行われたのかを包括的に説明するのに苦労していますsignificantly method 1よりも遅い...

方法は旧式のソリューションです-問題にCを投げます! PODタイプで問題なく高速に動作します。この場合、memcpyはベクターの境界外で動作し、ベクターにサイズが変更されたことを伝える方法がないため、resizeを呼び出す必要があります。 byteい解決策(バイトコピー!)であることに加えて、これはPODタイプにのみ使用であることを忘れないでください。私はこのソリューションを決して使用しません。

方法4が最適な方法です。その意味は明確で、(通常)最速であり、あらゆるオブジェクトに対して機能します。このアプリケーションでこのメソッドを使用することには欠点はありません。

方法5は方法4の調整です。配列をベクトルにコピーしてから追加します。良いオプション-一般的に高速で明快です。

最後に、配列の代わりにベクトルを使用できることを知っていますか?関数がCスタイルの配列を想定している場合でも、ベクトルを使用できます。

vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");

それが誰かに役立つことを願っています!

191
MattyT

既存のデータを置き換えるだけの場合、これを行うことができます

std::vector<int> data; // evil global :)

void CopyData(int *newData, size_t count)
{
   data.assign(newData, newData + count);
}
31
Torlack

std :: copy はあなたが探しているものです。

11
luke

編集できるのは自分の回答だけなので、質問に対する他の回答から複合回答を作成します。答えてくれた皆さんに感謝します。

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));
6
bsruth
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 :-)
5
Antonio Ramasco

memcpyを避けてください。本当に必要な場合を除き、ポインター操作を台無しにする理由はありません。また、POD型(intなど)でのみ機能しますが、構築が必要な型を扱っている場合は失敗します。

3
Assaf Lavie

さらに別の答えとして、「私の関数が何回呼び出されるかわからない」と言われたため、そのようなベクトル挿入メソッドを使用して、値の配列をベクトルの最後に追加できます。

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));
}
2
Shane Powell

上記のメソッドに加えて、std :: Vector.reserve()、std :: Vector.resize()のいずれかを使用するか、サイズに合わせてベクターを構築し、ベクターに十分な要素があることを確認する必要があります。データを保持します。そうでない場合、メモリが破損します。これは、std :: copy()またはmemcpy()のいずれにも当てはまります。

これがvector.Push_back()を使用する理由です。ベクトルの終わりを超えて書き込むことはできません。

1

ベクター内のアイテムの大きさがわかっていると仮定します。

std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));

http://www.cppreference.com/wiki/stl/vector/start

0