2008-11-03 4 views
72

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

ответ

80

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

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

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

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

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

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

3

Поскольку я могу только отредактировать свой собственный ответ, я собираюсь составить сложный ответ из других ответов на мой вопрос. Спасибо всем, кто ответил.

Используя 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)); 
+0

Я собирался рекомендовать этот подход. – mmocny 2008-11-03 17:09:00

+0

Скорее всего, более эффективно изменять размер вашего вектора вперед, если вы знаете размер раньше времени, а не использовать back_inserter. – luke 2008-11-03 17:09:48

+0

вы можете добавить my_data.reserve (размер) – 2008-11-03 17:10:40

0

Предполагая, что вы знаете, как большой элемент в векторе являются:

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

Это не зависит от реализации std :: vector? – ReaperUnreal 2008-11-03 17:50:13

+0

Это ужасно! Вы заполняете массив дважды, один с «0», а затем с соответствующими значениями. Просто выполните: std :: vector myArray (источник, источник + item_count); и доверяйте своему компилятору для создания memcpy! – 2008-11-03 17:54:31

2

избежать тетсру, я говорю. Нет причин вмешиваться в операции указателя, если вам действительно не нужно. Кроме того, он будет работать только для типов POD (например, int), но сработает, если вы работаете с типами, требующими построения.

1

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

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

24

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

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

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

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

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

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

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

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

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

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

1
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 :-)