Shallow copy (copie superficielle) – ne copie que les valeurs des champs de l'objet, y compris les pointeurs, mais ne duplique pas la mémoire allouée dynamiquement. En conséquence, les deux objets pointent vers la même région de mémoire. Cela peut entraîner des erreurs lors de la modification des données ou de la libération de la mémoire.
Deep copy (copie profonde) – crée une copie complète de toutes les ressources auxquelles l'objet fait référence, afin que chaque objet possède sa propre copie des données.
Quand deep copy est nécessaire :
Exemple de mise en œuvre de la deep copy :
class ArrayHolder { public: ArrayHolder(size_t size) : sz(size), data(new int[size]) {} ~ArrayHolder() { delete[] data; } // Constructeur de copie profonde ArrayHolder(const ArrayHolder& other) : sz(other.sz), data(new int[other.sz]) { std::copy(other.data, other.data + other.sz, data); } // Opérateur d'assignation de copie profonde 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; };
Question : Le constructeur de copie fonctionnera-t-il correctement si on copie simplement la valeur du pointeur ?
Réponse : Non, cela entraînera une double suppression de la mémoire lors de la destruction des deux objets. Il est nécessaire de mettre en œuvre une copie profonde pour une gestion correcte des ressources.
Histoire
Dans l'un des projets pour le transfert de tableaux entre les modules, des objets de classe étaient utilisés, dans lesquels le constructeur de copie par défaut ne copié que le pointeur (shallow copy). En conséquence, après la sortie de l'objet temporaire de la portée, le tableau était détruit, tandis que l'objet principal restait avec un pointeur "dangling", ce qui entraînait un comportement indéfini et un plantage de l'application.
Histoire
Dans une bibliothèque pour le traitement d'images, des objets contenant des tampons alloués dynamiquement étaient copiés à plusieurs reprises. En raison de l'absence de deep copy, après la libération de la mémoire dans un objet, un autre accédait à une zone libérée. Cela entraînait tant des corruptions de données que des plantages lors de la suppression de l'objet.
Histoire
Lors de l'intégration d'un code obsolète avec des normes modernes, aucun constructeur de copie ni opérateur d'assignation n'avait été mis en œuvre dans les anciennes classes. L'utilisation de ces classes avec des conteneurs de la bibliothèque standard entraînait des pannes inattendues, car les conteneurs copiaient les objets de manière superficielle.