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

StackOverflow https://stackoverflow.com/questions/259297

  •  06-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

... при условии, что a - это ваш массив, а n - это число элементов, которые он содержит. В противном случае std :: copy () w / 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 на проблему! Работает нормально и быстро для типов POD. В этом случае необходимо вызывать изменение размера, так как memcpy работает за пределами вектора, и нет никакого способа сообщить вектору, что его размер изменился. Помимо того, что это некрасивое решение (байтовое копирование!), Помните, что это может использоваться только для типов POD . Я бы никогда не использовал это решение.

Метод 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));
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 :-)

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

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

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

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

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top