У меня есть массив значений, который передается моей функции из другой части программы, которую мне нужно сохранить для последующей обработки. Поскольку я не знаю, сколько раз моя функция будет вызвана до того, как пришло время обрабатывать данные, мне нужна динамическая структура хранения, поэтому я выбрал std::vector
. Я не хочу делать стандартный цикл до push_back
всех значений по отдельности, было бы неплохо, если бы я мог просто скопировать все, используя что-то похожее на memcpy
.Как скопировать содержимое массива в std :: vector в C++ без цикла?
ответ
Если вы можете построить вектор после того, как вы получили массив и массив размера, вы можете просто сказать:
std::vector<ValueType> vec(a, a + n);
... если предположить a
ваш массив и n
это число элементов в нем , В противном случае std::copy()
w/resize()
сделает трюк.
Я бы держался подальше от memcpy()
, если вы не можете быть уверены, что значения являются типами простых данных (POD).
Кроме того, стоит отметить, что ни один из них не позволяет избежать цикла for - это всего лишь вопрос о том, нужно ли вам видеть его в коде или нет. O (n) производительность выполнения неизбежна для копирования значений.
Наконец, следует отметить, что массивы C-типа совершенно правомерные контейнеры для большинства алгоритмов STL - исходный указатель эквивалентен begin()
, и (ptr + n
) эквивалентно end()
.
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));
Предполагая, что вы знаете, как большой элемент в векторе являются:
std::vector<int> myArray;
myArray.resize (item_count, 0);
memcpy (&myArray.front(), source, item_count * sizeof(int));
Это не зависит от реализации std :: vector? – ReaperUnreal 2008-11-03 17:50:13
Это ужасно! Вы заполняете массив дважды, один с «0», а затем с соответствующими значениями. Просто выполните: std :: vector
избежать тетсру, я говорю. Нет причин вмешиваться в операции указателя, если вам действительно не нужно. Кроме того, он будет работать только для типов POD (например, int), но сработает, если вы работаете с типами, требующими построения.
В дополнение к методам, представленным выше, вам необходимо убедиться, что вы используете std :: Vector.reserve(), std :: Vector.resize() или конструируете вектор по размеру, чтобы убедиться, что ваш вектор имеет достаточно элементов для хранения ваших данных. если нет, вы испортите память. Это относится как к std :: copy(), так и к memcpy().
Это причина использования vector.push_back(), вы не можете писать мимо конца вектора.
Если все, что вы делаете, заменяя существующие данные, то вы можете сделать это
std::vector<int> data; // evil global :)
void CopyData(int *newData, size_t count)
{
data.assign(newData, newData + count);
}
еще один ответ, так как человек сказал: «Я не знаю, сколько раз моя функция будет называться» , вы можете использовать метод векторной вставки как и добавлять массивы значений к концу вектора:
vector<int> x;
void AddValues(int* values, size_t size)
{
x.insert(x.end(), values, values+size);
}
Мне нравится этот путь, потому что реализация вектора должна быть в состоянии оптимизировать лучший способ для вставки значения, основанные на типе итератора и самом типе. Вы несколько отвечаете на реализацию stl.
Если вам нужно, чтобы гарантировать максимальную скорость, и вы знаете, что ваш тип тип POD, то я рекомендовал бы метод изменения размера в ответ Томаса:
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));
}
Там было много ответов здесь и просто обо всем они получат работу.
Однако есть некоторые вводящие в заблуждение советы!
Вот варианты:
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, используя вектор :: вставки, является лучшим для сценария bsruth в.
Вот некоторые окровавленные детали:
Метод 1 вероятно, самый простой для понимания. Просто скопируйте каждый элемент из массива и вставьте его в обратную сторону вектора. Увы, это медленно. Поскольку существует цикл (подразумевается с функцией копирования), каждый элемент должен обрабатываться индивидуально; никакие улучшения производительности не могут быть сделаны на основе того факта, что мы знаем, что массив и векторы являются смежными блоками.
Способ 2 - предлагаемое улучшение производительности по методу 1; просто предварительно зарезервируйте размер массива перед его добавлением. Для больших массивов это может помочь. Однако лучший совет здесь - никогда не использовать резерв, если профилирование не предполагает, что вы сможете добиться улучшения (или вам нужно, чтобы ваши итераторы не были признаны недействительными). Bjarne agrees. Кстати, я обнаружил, что этот метод выполняется медленный большую часть времени, хотя я изо всех сил, чтобы всесторонне объяснить, почему это было регулярно значительно медленнее, чем метод 1 ...
Метод 3 старая школа решение - бросьте C на проблему! Работает отлично и быстро для типов POD. В этом случае требуется изменить размер, так как memcpy работает вне границ вектора, и нет способа сообщить вектору, что его размер изменился. Помимо того, что это уродливое решение (байтовое копирование!), Помните, что это может использоваться только для типов POD. Я бы никогда не использовал это решение.
Способ 4 - лучший способ пойти. Это значение ясно, оно (обычно) самое быстрое и работает для любых объектов. Нет недостатка в использовании этого метода для этого приложения.
Способ 5 - это настройка по методу 4 - копирование массива в вектор, а затем добавление его. Хороший вариант - обычно быстрый и понятный.
Наконец, вы знаете, что вы можете использовать векторы вместо массивов, не так ли? Даже если функция ожидает c-style массивы, вы можете использовать векторы:
vector<char> v(50); // Ensure there's enough space
strcpy(&v[0], "prefer vectors to c arrays");
Надеюсь, что кто-то поможет!
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 :-)
Я собирался рекомендовать этот подход. – mmocny 2008-11-03 17:09:00
Скорее всего, более эффективно изменять размер вашего вектора вперед, если вы знаете размер раньше времени, а не использовать back_inserter. – luke 2008-11-03 17:09:48
вы можете добавить my_data.reserve (размер) – 2008-11-03 17:10:40