Wie können Sie Ihre STL-Container kopieren?
// big containers of POD
container_type<pod_type> source;
container_type<pod_type> destination
// case 1
destination = source;
// case 2
destination.assign(source.begin(), source.end());
// case 3 assumes that destination.size() >= source.size()
copy(source.begin(), source.end(), destination.size());
Ich verwende Fall 1, wann immer es möglich ist. Fall 2 gilt für Container verschiedener Typen. Fall 3 wird benötigt, wenn das Ziel größer ist als die Quelle und Sie die verbleibenden Elemente behalten wollen.
Aber wie sieht es mit Nicht-POD-Elementen aus, deren Bau-/Zerstörungskosten nicht Null sind? Kann Fall 3 besser sein als Fall 2? Wenn das Ziel größer ist als die Quelle, kann die Implementierung ziemlich unerwartete Dinge tun. Das ist es, was Visual Studio 2008 im Fall 2 tut.
- Alle Elemente des Ziels werden zerstört.
- Dann wird der Kopierkonstruktor so oft aufgerufen, wie die Größe des Ziels beträgt. Warum?
- Alle Elemente der Quelle werden den entsprechenden Elementen des Ziels zugeordnet.
- Die zusätzlichen Elemente des Ziels werden zerstört.
GCC 4.5 macht es besser. Alle Elemente der Quelle werden per Zuweisung kopiert und dann werden die zusätzlichen Elemente des Ziels zerstört. Die Verwendung von Fall 3 gefolgt von Größe ändern tut auf beiden Plattformen das Gleiche (mit Ausnahme eines Standardkonstruktors, der Größe ändern Bedürfnisse). Hier ist das Spielzeugprogramm, das zeigt, was ich meine.
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
using namespace std;
struct A {
A() { cout << "A()\n"; }
A(const A&) { cout << "A(const A&)\n"; }
A& operator=(const A&) {
cout << "operator=\n";
return *this;
}
~A() { cout << "~A()\n"; }
};
int main() {
list<A> source(2);
vector<A> desrination1(3);
vector<A> desrination2(3);
cout << "Use assign method\n";
desrination1.assign(source.begin(), source.end());
cout << "Use copy algorithm\n";
copy(source.begin(), source.end(), desrination2.begin());
desrination2.resize(2);
cout << "The End" << endl;
return 0;
}