Copy-Konstruktor und Copy-Zuweisungsoperator sind notwendig für die Arbeit mit Objekten, die Ressourcen besitzen (zum Beispiel dynamischen Speicher). Standardmäßig generiert der Compiler eine bitweise Kopie, was für rohe Zeiger gefährlich ist:
class Buffer { public: Buffer(size_t size) { data = new int[size]; this->size = size; } ~Buffer() { delete[] data; } // Korrekte Implementierung des Copy-Konstruktors Buffer(const Buffer& other) : size(other.size) { data = new int[size]; std::copy(other.data, other.data + size, data); } // Korrekter Zuweisungsoperator Buffer& operator=(const Buffer& other) { if (this != &other) { delete[] data; size = other.size; data = new int[size]; std::copy(other.data, other.data + size, data); } return *this; } private: int* data; size_t size; };
Ansonsten kann es beim Kopieren von zwei Objekten dazu kommen, dass eines den Speicher freigibt, während das andere mit einem hängenden Zeiger bleibt (double free oder use after free).
Was passiert, wenn man nur den Copy-Konstruktor deklariert, aber nicht den Zuweisungsoperator? Wann ist er nötig, und wann nicht?
Antwort: Wenn nur der Copy-Konstruktor deklariert ist, aber der Zuweisungsoperator nicht, generiert der Compiler einen Standard-Zuweisungsoperator (bitweises Kopieren), was gefährlich ist, wenn das Objekt dynamische Ressourcen enthält, d. h. es wird denselben Zeiger zweimal freigeben.
Im Fall des Speicherverwaltung müssen beide implementiert werden: der Copy-Konstruktor und der Zuweisungsoperator, um Kopierfehler/Speicherlecks zu vermeiden.
Geschichte
In einem Medienserver wurde beim Kopieren eines Buffer-Objekts der Copy-Konstruktor verwendet, aber der Zuweisungsoperator vergessen. Wenn ein Buffer einem anderen zugewiesen wurde, kam es zu doppelter Speicherfreigabe beim Zerstören der Objekte. Der Fehler trat bei Stresstests auf.
Geschichte
In einem Projekt zur Transportlogistik kopierte der Standard-Zuweisungsoperator eine Struktur mit einem Zeiger auf ein Array von Koordinaten. Nach der Löschung eines Objekts adressierte das zweite zur freigegebenen Speicher, was zu Segmentierungsfehlern führte.
Geschichte
In einem der Projekte mit grafischen Ressourcen wurde der Copy-Konstruktor bei der Übertragung von Objekten zwischen Threads vergessen. Die Übertragung durch Wert führte zu einer flachen Kopie, und nach der Änderung des Objekts in einem anderen Thread kam es zu Datenbeschädigungen und Programmabstürzen.