Schneller Weg, um einen Vektor in einen anderen zu kopieren


155

Ich bevorzuge zwei Möglichkeiten:

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

Wie machst du das?


14
Der zweite hat einen irreführenden Namen - da es sich nicht um eine Kopie handelt (obwohl sie schnell ist).
Anonym

Antworten:


126

Ihr zweites Beispiel funktioniert nicht, wenn Sie das Argument als Referenz senden. Meintest du

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

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

Das würde funktionieren, ist aber einfacher

vector<int> new_(original);

Gut, es funktioniert. Aber es funktioniert nicht für ein Array von Vektoren: zum Beispiel: vector <int> A [n];
ABcDexter

8
Das ist Tausch, nicht Kopie.
SDD

1
@sdd - nein ist es nicht. Überprüfen Sie die Argumentliste. originalist eine Kopie des Funktionsarguments.
Rlbond

249

Sie sind aber nicht die gleichen, oder? Einer ist eine Kopie, der andere ist ein Tausch . Daher die Funktionsnamen.

Mein Favorit ist:

a = b;

Wo aund bsind Vektoren.


3
Tatsächlich wird der Ansatz als Wert übergeben, der Compiler ruft den Kopierkonstruktor auf und tauscht dann das neu erstellte Element aus. Aus diesem Grund schlägt rlbond vor, den Kopierkonstruktor direkt aufzurufen, um den gleichen Effekt zu erzielen.
David Rodríguez - Dribeas

1
Sie können rlbon jedoch nicht ohne eine Funktion aufrufen, die das Original als val übergibt. Andernfalls wird das Original geleert. Die zweite Lösung hat sichergestellt, dass Sie immer nach Wert aufrufen und somit das Datum im ursprünglichen Vektor nicht verlieren. (Angenommen, Swap befasst sich mit Zeigern)
Eyad Ebrahim

Verschiebt das nicht die Elemente von b nach a (wobei b mit der Größe == 0 belassen wird)?
Jonathan.

1
@ Jonathan. Angenommen, Sie sprechen von a = bdann nein. Aufgabe bedeutet: aGleich machen, bohne sich zu ändern b. Im Gegensatz dazu std::swap(a, b)würden ihre Inhalte austauschen (so bist sizejetzt wäre , was a's vor gewesen war). Sie denken vielleicht an eine Verschiebungsoperation (wie sie in C ++ 11 vorkommt, aber nicht in einer gewöhnlichen Aufgabe wie dieser). Ein solcher Schritt würde bin einem, ähm, "interessanten" Zustand ablaufen
Daniel Earwicker

1
@ Jonathan. Beachten Sie das doppelte kaufmännische Und &&. Diese Version wird nur als Referenz verwendet. Es stimmt nicht mit einem nicht konstanten Wert überein (wie bin meinem obigen Beispiel). Sie können sich bin eine verwandeln, indem Sie sagen: a = std::move(b);Siehe en.cppreference.com/w/cpp/language/value_category für noch mehr Komplexität.
Daniel Earwicker

74

Dies ist eine weitere gültige Methode zum Erstellen einer Kopie eines Vektors. Verwenden Sie einfach dessen Konstruktor:

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

Dies ist noch einfacher, als std::copyden gesamten Vektor von Anfang bis Ende zu durchlaufenstd::back_insert in den neuen Vektor zu verschieben.

Davon abgesehen ist Ihre .swap()keine Kopie, sondern vertauscht die beiden Vektoren. Sie würden das Original so ändern, dass es nichts mehr enthält! Welches ist keine Kopie.


19

Direkte Antwort:

  • Verwenden Sie einen =Operator

Wir können die public member-Funktion std::vector::operator=des Containers verwenden, std::vectorum Werte von einem Vektor einem anderen zuzuweisen.

  • Verwenden Sie eine Konstruktorfunktion

Außerdem ist eine Konstruktorfunktion sinnvoll. Eine Konstruktorfunktion mit einem anderen Vektor als Parameter (z. B. x) erstellt einen Container mit einer Kopie jedes der Elemente inx derselben Reihenfolge.

Vorsicht:

  • Verwende nicht std::vector::swap

std::vector::swapist nicht das Kopieren eines Vektors zu einem anderen, ist es tatsächlich Elemente zweier Vektoren Swapping, wie der Name vermuten lässt. Mit anderen Worten, der Quellvektor, von dem kopiert werden soll, wird nach dem std::vector::swapAufruf geändert , was wahrscheinlich nicht das ist, was Sie erwarten.

  • Tiefe oder flache Kopie?

Wenn die Elemente im Quellvektor Zeiger auf andere Daten sind, ist manchmal eine tiefe Kopie erwünscht.

Laut Wikipedia:

Eine tiefe Kopie, dh, Felder werden dereferenziert: Anstelle von Verweisen auf zu kopierende Objekte werden für alle referenzierten Objekte neue Kopierobjekte erstellt und Verweise auf diese in B platziert.

Tatsächlich gibt es derzeit in C ++ keine integrierte Möglichkeit, eine tiefe Kopie zu erstellen. Alle oben genannten Wege sind flach. Wenn eine tiefe Kopie erforderlich ist, können Sie einen Vektor durchlaufen und die Referenzen manuell kopieren. Alternativ kann ein Iterator zum Durchlaufen in Betracht gezogen werden. Die Diskussion über den Iterator geht über diese Frage hinaus.

Verweise

Die Seite von std::vectorauf cplusplus.com


14

Sie sollten Swap nicht zum Kopieren von Vektoren verwenden, da dies den "ursprünglichen" Vektor ändern würde.

Übergeben Sie stattdessen das Original als Parameter an das Neue.


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

-14

Falls der Vektor BEREITS vorhanden war und Sie nur kopieren wollten, können Sie Folgendes tun:

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

1
Bitte nicht merken. Dies funktioniert auch nicht, da memcpy die Größe in Bytes annimmt. Auch wenn der andere Vektor bereits vorhanden ist, können Sie dies einfach tun, newVec = oldVecwas mit einer der anderen Antworten identisch ist.
FDinoff

Ja, du hast recht. Das habe ich nicht gesehen. @FDinoff, obwohl unten eine funktioniert, warum schlagen Sie vor, memcpy nicht zu verwenden? Es scheint viel schneller zu sein als newVec = oldVec. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd

1
Im allgemeinen Fall kann das Kopieren eines Objekts ohne Aufrufen seines Kopierkonstruktors zu subtilen Fehlern führen. In diesem Fall hätte ich gedacht, dass sie die gleiche Leistung gehabt hätten. Wenn dies nicht der Fall wäre, würde ich sagen, dass der Vektor nicht leistungsoptimiert ist, da dies bereits geschehen sollte. Haben Sie tatsächlich einen Benchmark geschrieben?
FDinoff

Ich habe dich nicht kritisiert. Mein Teamleiter schlug dasselbe vor und ich versuchte zu verstehen.
sgowd

(Ich dachte nicht, dass Sie mich kritisieren.) Gibt es noch etwas, das Sie nicht verstehen?
FDinoff
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.