ProgrammierungC++ Entwickler

Was passiert bei der Übergabe eines Objekt der Klasse per Wert an eine Funktion und welche Fallstricke sind bei der Implementierung des Kopierkonstruktors zu beachten?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

Bei der Übergabe eines Objekts per Wert an eine Funktion in C++ passiert die Erstellung einer Kopie des Objekts mithilfe des Kopierkonstruktors. Wenn in der Klasse ein benutzerdefinierter Kopierkonstructor definiert ist, wird dieser aufgerufen, um das temporäre Objekt-Argument der Funktion zu initialisieren. Wenn kein solcher definiert ist, wird der standardmäßige Compiler verwendet, der eine bitweise Kopie (shallow copy) durchführt.

Fallstricke:

  • Wenn die Klasse Ressourcen verwaltet (z.B. rohe Zeiger hat), führt der standardmäßig generierte Kopierkonstruktor zu Fehlern des doppelten Freigabens des Speichers und zu Lecks.
  • Es muss sichergestellt werden, dass der Kopierkonstruktor die Ressourcen korrekt kopiert (normalerweise deep copy).

Beispiel:

class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Fehler: shallow copy StringWrapper(const StringWrapper& other) : data(other.data) {} ~StringWrapper() { delete [] data; } }; void foo(StringWrapper s) { // ... } int main() { StringWrapper s1("hello"); foo(s1); // UB!!! return 0; }

Fangfrage

"Was passiert, wenn der Kopierkonstruktor in einer Klasse mit einem Zeiger so definiert wird: MyClass(const MyClass &other) : data(other.data) {}? Welche Folgen hat das?"

Richtige Antwort: Ein solcher Kopierkonstruktor erstellt ein Objekt mit einem Zeiger auf denselben Speicherbereich wie das kopierte Objekt. Bei der Zerstörung der beiden Objekte wird der Speicher zweimal freigegeben (double free), was zu undefiniertem Verhalten führt. Es sollte eine deep copy implementiert werden:

MyClass(const MyClass &other) { data = new int(*other.data); }

Beispiele für reale Fehler aufgrund von Unkenntnis der Feinheiten des Themas


Geschichte

In einem großen Serverprojekt wurden Container aus Objekten mit einem "rohen" Array darin und dem standardmäßigen Kopierkonstruktor (shallow copy) verwendet. Bei der Übergabe von Objekten per Wert traten double free und Anwendungsabstürze auf, die nur in der Produktion erfasst wurden.


Geschichte

In einer alten C++-Bibliothek zur Verarbeitung von Bildern kopierte der Kopierkonstruktor den Grafikpuffer nicht, was dazu führte, dass sich eine Kopie des Bildes änderte, wenn die andere geändert wurde, und unerwartete Bugs in der Benutzeroberfläche auftraten.


Geschichte

Beim Zurückgeben eines Objekts per Wert aus einer Funktion in einem der internen Passwortspeichersysteme wurden die Daten beim Zerstören des temporären Objekts (shallow copy) gelöscht, wodurch das echte Objekt einen nullzeiger enthielt, und das Leck wurde zufällig während einer Sicherheitsüberprüfung entdeckt.