Shallow copy (oppervlakkige kopie) kopieert alleen de waarden van de velden van een object, inclusief pointers, maar dupliceert geen dynamisch toegewezen geheugen. Dit betekent dat beide objecten naar hetzelfde geheugenadres verwijzen. Dit kan leiden tot fouten bij het wijzigen van gegevens of het vrijgeven van geheugen.
Deep copy (diepe kopie) maakt een volledige kopie van alle bronnen waaraan het object verwijst, zodat elk object zijn eigen kopie van de gegevens bezit.
Wanneer heb je deep copy nodig:
Voorbeeld van implementatie van deep copy:
class ArrayHolder { public: ArrayHolder(size_t size) : sz(size), data(new int[size]) {} ~ArrayHolder() { delete[] data; } // Diepe kopieconstructor ArrayHolder(const ArrayHolder& other) : sz(other.sz), data(new int[other.sz]) { std::copy(other.data, other.data + other.sz, data); } // Diepe kopie-toewijzing ArrayHolder& operator=(const ArrayHolder& other) { if (this != &other) { delete[] data; sz = other.sz; data = new int[sz]; std::copy(other.data, other.data + sz, data); } return *this; } private: size_t sz; int* data; };
Vraag: Zal de kopieconstructor correct werken als je gewoon de waarde van de pointer kopieert?
Antwoord: Nee, dit zal leiden tot dubbele vrijgave van geheugen bij het vernietigen van beide objecten. Het is noodzakelijk om diepe kopie te implementeren voor een correcte resourcebeheer.
Verhaal
In een van de projecten werden objecten van de klasse gebruikt voor het overdragen van arrays tussen modules, waarbij de standaard kopieconstructor alleen de pointer kopieerde (shallow copy). Als gevolg hiervan, na het verlaten van het tijdelijke object uit de scope, werd de array vernietigd, terwijl het hoofdobject met een "hangende" pointer bleef, wat leidde tot onbepaald gedrag en een crash van de applicatie.
Verhaal
In de bibliotheek voor het werken met afbeeldingen werden objecten die dynamisch toegewezen buffers bevatten, meerdere keren gekopieerd. Door het ontbreken van deep copy kreeg een object, na het vrijgeven van geheugen in een ander object, toegang tot het vrijgegeven gebied. Dit leidde tot zowel gegevensbeschadiging als crashes bij het verwijderen van het object.
Verhaal
Bij de integratie van verouderde code met moderne standaarden waren in de oude klassen noch de kopieconstructor noch de toewijzingsoperator geïmplementeerd. Het gebruik van deze klassen met containers van de standaardbibliotheek leidde tot onverwachte crashes, omdat de containers de objecten oppervlakkig kopieerden.