швидкий спосіб копіювання одного вектора в інший


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
Другий має оманливу назву - оскільки це не копія (хоча вона швидка).
Анонім

Відповіді:


126

Ваш другий приклад не працює, якщо ви надсилаєте аргумент за посиланням. Ти мав на увазі

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

249

Хоча вони не однакові, чи не так? Один - це копія, інший - своп . Звідси імена функцій.

Мій улюблений:

a = b;

Де aі bє вектори.


3
Насправді підхід передається за значенням, компілятор викликає конструктор копій, а потім міняє цей новостворений елемент. Ось чому rlbond пропонує викликати конструктор копій безпосередньо для досягнення того ж ефекту.
Девід Родрігес - дрибес

1
Однак ви не можете викликати rlbon без функції, яка передає оригінал як val. В іншому випадку оригінал буде порожнім. Друге рішення гарантувало, що ви завжди будете дзвонити за значенням і, отже, не втратите дату у вихідному векторі. (Припустимо, що угоди про своп угоди з покажчиками)
Еяд Ебрагім

Хіба це не перемістить елементи b в a (залишивши b з розміром == 0)?
Джонатан.

1
@Jonathan. Якщо припустити, що ти говориш про це, a = bто ні. Призначення означає: зробити aрівним bбез зміни b. На противагу цьому , std::swap(a, b)проміняє їх зміст (так b«s sizeтепер буде те , що a" s було раніше). Ви, напевно, думаєте про операцію переміщення (як це відбувається у C ++ 11, але не в звичайному завданні, як це). Такий хід залишить bу "ах" "цікавому" стані - див. Stackoverflow.com/questions/17730689/…
Daniel Earwicker

1
@Jonathan. Зверніть увагу на подвійний амперсанд &&. Ця версія буде використовуватися лише для посилання на оцінку. Він не відповідає жодному значенню non-const (наприклад,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()не є копією, він заміняє два вектори. Ви б змінили оригінал, щоб він більше нічого не містив! Що не є копією.


19

Пряма відповідь:

  • Використовуйте =оператора

Ми можемо використовувати функцію public member 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.