ProgrammationDéveloppeur C++

Expliquez la différence entre shallow copy et deep copy en prenant l'exemple d'un conteneur avec de la mémoire dynamique. Comment réaliser correctement une copie profonde ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Le shallow copy (copie superficielle) ne copie que les valeurs des membres de la classe, y compris les pointeurs — mais ne copie pas les données pointées. Le deep copy (copie profonde) crée de nouvelles copies des données auxquelles pointent les pointeurs, ce qui empêche la possession partagée de la mémoire et la double libération.

Exemple :

class Buffer { public: Buffer(size_t size) : size(size), data(new int[size]) {} // Shallow copy (incorrect) Buffer(const Buffer& other) : size(other.size), data(other.data) {} // Deep copy (correct) Buffer& operator=(const Buffer& other) { if (this != &other) { delete[] data; size = other.size; data = new int[size]; std::copy(other.data, other.data + size, data); } return *this; } ~Buffer() { delete[] data; } private: size_t size; int* data; };

Question piège.

Si la classe contient un pointeur vers un tableau dynamique, pourquoi ne suffit-il pas de copier-coller le constructeur de copie et l'opérateur= par défaut ?

Réponse correcte :

La copie par défaut implémente une copie superficielle. Deux objets pointeront vers le même tableau, et lors de la destruction, il y a une tentative de libérer deux fois la même mémoire (double free), ce qui entraînera un crash.

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


Histoire Dans une grande application serveur, une classe Image a été mise en œuvre pour gérer un tampon dynamique de pixels. Les développeurs n'ont pas implémenté de copie profonde, et lors de la transmission d'objets Image par valeur entre les threads, une double libération de mémoire se produisait, entraînant des crashs tous les quelques jours.


Histoire Dans un projet étudiant, un conteneur Field était utilisé, contenant un pointeur vers un tableau de cellules alloué dynamiquement. Lors du changement de taille du tableau, le constructeur de copie ne copiait que le pointeur, et les deux conteneurs travaillaient avec la même zone de mémoire, ce qui entraînait des données incohérentes et des bogues difficiles à trouver.


Histoire Dans un ancien code C++ d'un moteur graphique, une classe Texture a été implémentée sans son destructeur et son opérateur d'affectation, ce qui a entraîné des fuites de mémoire lors de la copie et de l'affectation d'objets temporaires de textures.