быстрый способ скопировать один вектор в другой


155

Я предпочитаю два способа:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

Как ты это делаешь?


14
Второе имя вводит в заблуждение - поскольку это не копия (хотя это быстро).
Аноним

Ответы:


125

Ваш второй пример не работает, если вы отправляете аргумент по ссылке. Вы имели в виду

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

Это будет работать, но более простой способ

vector<int> new_(original);

Хорошо, это работает. Но это не работает для массива векторов: например: vector <int> A [n];
ABcDexter

8
Это обмен, а не копирование.
SDD

1
@sdd - нет, это не так. Проверьте список аргументов. originalявляется копией аргумента функции.
rlbond

@rlbond Случайно понизил ответ :(, Можете ли вы отредактировать сообщение, чтобы я мог убрать понижение и дать возражение?
Шубхам Шарма

250

Они не одинаковы, правда? Один - копия, другой - своп . Отсюда и имена функций.

Мой любимый это:

a = b;

Где aи bнаходятся векторы.


3
Фактически, подход передается по значению, компилятор вызывает конструктор копирования, а затем заменяет этот вновь созданный элемент. Вот почему rlbond предлагает вызвать конструктор копирования напрямую для достижения того же эффекта.
Дэвид Родригес - dribeas

1
Однако вы не можете вызвать rlbon без функции, которая передает оригинал как val. В противном случае оригинал будет пустым. Второе решение гарантировало, что вы всегда будете звонить по значению и, следовательно, вы не потеряете дату в исходном векторе. (Предполагается, что своп имеет дело с указателями)
Eyad Ebrahim

Разве это не переместит элементы b в a (оставив b с размером == 0)?
Джонатан.

1
@Джонатан. Предполагая, что вы говорите, a = bто нет. Назначение означает: сделать aравными bбез изменения b. В противоположность этому , std::swap(a, b)променяет их содержание (так b«s sizeтеперь будет то , что a» s было раньше). Возможно, вы думаете об операции перемещения (как это происходит в C ++ 11, но не в обычном присваивании, подобном этому). Такой шаг мог бы оставить bв ап, гм, «интересно» состояние - см stackoverflow.com/questions/17730689/...
Daniel Earwicker

1
@Джонатан. Обратите внимание на двойной амперсанд &&. Эта версия будет использоваться только для ссылки. Это не будет соответствовать ни одному неконстантному значению (как bв моем примере выше). Вы можете превратиться bв один, сказав a = std::move(b);Смотрите en.cppreference.com/w/cpp/language/value_category для еще больших уровней сложности.
Даниэль Эрвикер

74

Это еще один правильный способ сделать копию вектора, просто используйте его конструктор:

std::vector<int> newvector(oldvector);

Это даже проще, чем использовать std::copyдля перехода весь вектор от начала до конца к std::back_insertновому вектору.

При этом ваш .swap()экземпляр не является копией, он заменяет два вектора. Вы бы изменили оригинал, чтобы больше ничего не содержать! Который не является копией.


Более гибким для меня является то, a = b;что у меня уже есть поле участника, aи мне просто нужно присвоить ему новое значение отb
trueadjustr

20

Прямой ответ:

  • Используйте =оператора

Мы можем использовать открытую функцию-член std::vector::operator=контейнера std::vectorдля назначения значений из вектора в другой.

  • Используйте функцию конструктора

Кроме того, функция конструктора также имеет смысл. Функция конструктора с другим вектором в качестве параметра (например,x ) создает контейнер с копией каждого из элементов xв том же порядке.

Внимание:

  • Не используй std::vector::swap

std::vector::swapэто не копирование вектора в другой, это на самом деле замена элементов двух векторов, как и предполагает его название. Другими словами, исходный вектор для копирования изменяется после std::vector::swapвызова, что, вероятно, не то, что вы ожидаете.

  • Глубокая или мелкая копия?

Если элементы в исходном векторе являются указателями на другие данные, то иногда требуется глубокая копия.

Согласно википедии:

Глубокая копия, означающая, что поля разыменовываются: вместо ссылок на копируемые объекты создаются новые объекты копирования для любых ссылочных объектов, а ссылки на них помещаются в B.

На самом деле, в C ++ в настоящее время нет встроенного способа сделать глубокое копирование. Все вышеперечисленные способы мелкие. Если необходима глубокая копия, вы можете пройти вектор и сделать копии ссылок вручную. Альтернативно, итератор может рассматриваться для обхода. Обсуждение итератора выходит за рамки этого вопроса.

Ссылки

Страница std::vectorна cplusplus.com


14

Вы не должны использовать swap для копирования векторов, это изменит «оригинальный» вектор.

вместо этого передайте оригинал в качестве параметра новому.


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

Если вектор УЖЕ существует и вы хотите просто скопировать, вы можете сделать это:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
Пожалуйста, не memcpy. Также это не будет работать, так как memcpy принимает размер в байтах. Также, если другой вектор уже существует, вы можете просто сделать newVec = oldVecто же самое, что и один из других ответов.
FDinoff

Да ты прав. Я этого не видел. @FDinoff, хотя ниже работает один, почему вы предлагаете не использовать memcpy? Кажется, это намного быстрее, чем newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd

1
В общем случае копирование объекта без вызова его конструктора копирования может привести к незначительным ошибкам. В этом случае я бы подумал, что они будут иметь одинаковую производительность. Если бы этого не произошло, я бы сказал, что вектор не оптимизирован по производительности, поскольку он уже должен был это делать. Вы действительно написали тест?
FDinoff

Я не критиковал тебя .. Мой руководитель команды также предложил то же самое, и я пытался понять.
sgowd

(Я не думал, что вы критиковали меня.) Есть ли что-то, чего вы не понимаете?
FDinoff
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.