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

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

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

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

Ответы:

125

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

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

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

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

vector<int> new_(original);
rlbond
источник
Хорошо, это работает. Но это не работает для массива векторов: например: 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()экземпляр не является копией, он заменяет два вектора. Вы бы изменили оригинал, чтобы больше ничего не содержать! Который не является копией.

X-Istence
источник
Более гибким для меня является то, 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 для копирования векторов, это изменит «оригинальный» вектор.

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

Raz
источник
14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2
FaridLU
источник
-14

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

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());
sgowd
источник
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