Bij het doorgeven van een object per waarde aan een functie in C++ vindt er een kopie van het object plaats met behulp van de kopieerconstructor. Als er een gebruikersgedefinieerde kopieerconstructor in de klasse is gedefinieerd, wordt deze aangeroepen om het tijdelijke argumentobject van de functie te initialiseren. Als er geen is gedefinieerd, wordt de standaard compiler gebruikt, die een bit voor bit kopieert (shallow copy).
Valkuilen:
Voorbeeld:
class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Fout: 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; }
"Wat gebeurt er als je de kopieerconstructor in een klasse met een pointer als volgt definieert:
MyClass(const MyClass &other) : data(other.data) {}? Welke gevolgen heeft dit?"
Juiste antwoord: Deze kopieerconstructor zal een object creëren met een pointer naar hetzelfde geheugen als het gekopieerde. Bij vernietiging van de twee objecten zal het geheugen twee keer worden vrijgegeven (double free), wat leidt tot onbepaald gedrag. Er moet een deep copy worden geïmplementeerd:
MyClass(const MyClass &other) { data = new int(*other.data); }
Verhaal
In een groot serverproject werden containers met objecten met een "ruwe" array erin gebruikt en de standaard kopieerconstructor (shallow copy). Bij het doorgeven van objecten per waarde trad double free op en crashten de applicaties, wat alleen in productie werd opgemerkt.
Verhaal
In een oude C++-bibliotheek voor het werken met afbeeldingen kopieerde de kopieerconstructor de grafische buffer niet, wat leidde tot het veranderen van één kopie van de afbeelding bij het veranderen van een andere en onverwachte bugs in de interface.
Verhaal
Bij het retourneren van een object per waarde uit een functie in een van de interne wachtwoordopslagsystemen werden de gegevens gewist bij vernietiging van het tijdelijke object (shallow copy), waardoor het echte object een gewiste pointer bevatte, en het lek toevallig tijdens een beveiligingsaudit werd ontdekt.