Как скопировать содержимое массива в std:: vector в C++ без цикла?


у меня есть массив значений, который передается в функцию из другой части программы, что мне нужно сохранить для последующей обработки. Поскольку я не знаю, сколько раз моя функция будет вызвана до того, как придет время обрабатывать данные, мне нужна динамическая структура хранения, поэтому я выбрал std::vector. Я не хочу делать стандартный цикл push_back все значения по отдельности, было бы неплохо, если бы я мог просто скопировать все это, используя что-то похожее на memcpy.

10 83

10 ответов:

если вы можете построить вектор после того, как вы получили массив и размер массива, вы можете просто сказать:

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

...предполагая, что a - это Ваш массив и n - это количество элементов, которые он содержит. В противном случае, std::copy() Вт/resize() будет делать трюк.

Я бы держался от memcpy() если вы не можете быть уверены, что значения являются простыми старыми типами данных (POD).

кроме того, стоит отметить, что ни один из них действительно не избегает цикла for-это просто вопрос независимо от того, должны ли вы видеть его в своем коде или нет. O (n) производительность среды выполнения неизбежна для копирования значений.

наконец, обратите внимание, что массивы C-стиля являются совершенно допустимыми контейнерами для большинства алгоритмов STL-необработанный указатель эквивалентен begin() и (ptr + n) равна end().

здесь было много ответов, и почти все они выполнят свою работу.

однако есть некоторые вводящие в заблуждение советы!

вот варианты:

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; просто предварительно зарезервируйте размер массива перед его добавлением. Для больших массивов это может помочь. Однако лучший совет здесь-никогда не использовать резерв, если профилирование не предполагает, что вы можете получить улучшение (или вам нужно убедиться, что ваши итераторы не будут признаны недействительными). Бьярне согласен. Кстати, я обнаружил, что этот метод выполняется самый медленный большую часть времени, хотя я изо всех сил пытаюсь всесторонне объяснить, почему это было регулярно значительно медленнее, чем метод 1...

Способ 3 - это старая школа решение-бросьте немного C на проблему! Работает отлично и быстро для типов стручков. В этом случае необходимо вызвать resize, так как memcpy работает за пределами вектора, и нет способа сообщить вектору, что его размер изменился. Помимо того, что это уродливое решение (копирование байтов!) помните, что это может используется только для типов стручков. Я бы никогда не использовал это решение.

метод 4 - это лучший способ пойти. Это означает, что ясно, это (обычно) самый быстрый и он работает для любых объектов. Нет никакого недостатка в использовании этого метода для этого приложения.

Метод 5 это настройка по методу 4-скопируйте массив в вектор, а затем добавьте его. Хороший вариант-вообще быстрый и понятный.

наконец, вы знаете, что вы можете использовать векторы вместо массивов, не так ли? Даже когда функция ожидает массивы в стиле c, вы можете использовать векторы:

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

надеюсь, что это поможет кому-то там!

Если все, что вы делаете, это замена существующих данных, то вы можете сделать это

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));

избегайте memcpy, я говорю. Нет причин возиться с операциями указателя, если вы действительно не должны. Кроме того, он будет работать только для типов POD (например, 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 :-)

в дополнение к методам, представленным выше, вам нужно убедиться, что вы используете либо std::Vector.reserve (), std::Vector.измените размер () или создайте вектор по размеру, чтобы убедиться, что в вашем векторе достаточно элементов для хранения ваших данных. если нет, вы повредите память. Это верно для std:: copy() или memcpy().

Это причина для использования вектора.push_back(), вы не можете писать за концом вектора.

еще один ответ, так как человек сказал: "Я не знаю, сколько раз моя функция будет вызвана", вы можете использовать метод векторной вставки, например, чтобы добавить массивы значений в конец вектора:

vector<int> x;

void AddValues(int* values, size_t size)
{
   x.insert(x.end(), values, values+size);
}

мне нравится этот способ, потому что реализация вектора должна быть в состоянии оптимизировать для лучшего способа вставки значений на основе типа итератора и самого типа. Вы несколько отвечаете на реализацию stl.

Если вам нужно гарантируйте самую быструю скорость, и вы знаете, что ваш тип-это тип стручка, тогда я бы рекомендовал метод изменения размера в ответе Томаса:

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));
}

предполагая, что вы знаете, насколько велик элемент в векторе:

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