ProgrammationDéveloppeur C++

Quelles sont les différences entre la shallow copy et la deep copy en C++ ? Dans quelles situations est-il nécessaire de réaliser soi-même une copie profonde, et comment le faire correctement ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

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 :

  • Lorsque l'objet possède une mémoire allouée dynamiquement.
  • Lorsque la modification du contenu d'un objet ne doit pas affecter un autre.

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 piège.

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.

Exemples d'erreurs réelles dues à l'ignorance des nuances du sujet.


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.