Lors du passage d'un objet par valeur à une fonction en C++, une copie de l'objet est créée à l'aide du constructeur de copie. Si un constructeur de copie personnalisé est défini dans la classe, il est appelé pour initialiser un objet temporaire, l'argument de la fonction. S'il n'est pas défini, le compilateur par défaut est utilisé, qui effectue une copie bit à bit (shallow copy).
Pièges :
Exemple :
class StringWrapper { char* data; public: StringWrapper(const char* str) { data = new char[strlen(str) + 1]; strcpy(data, str); } // Erreur : 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; }
"Que se passe-t-il si l'on définit le constructeur de copie dans une classe avec un pointeur comme ceci :
MyClass(const MyClass &other) : data(other.data) {}? Quelles conséquences cela engendre-t-il ?"
Réponse correcte : Un tel constructeur de copie créera un objet avec un pointeur vers la même zone de mémoire que celui copié. Lors de la destruction des deux objets, la mémoire sera libérée deux fois (double free), ce qui entraînera un comportement indéfini. Il faut implémenter une deep copy :
MyClass(const MyClass &other) { data = new int(*other.data); }
Histoire
Dans un grand projet serveur, des conteneurs d'objets avec un "tableau brut" à l'intérieur et un constructeur de copie standard (shallow copy) étaient utilisés. Lors du passage d'objets par valeur, cela a entraîné une double libération de mémoire et des plantages de l'application, détectés uniquement en production.
Histoire
Dans une ancienne bibliothèque C++ pour le traitement d'images, le constructeur de copie ne copiait pas le tampon graphique, ce qui entraînait la modification d'une copie de l'image lors de la modification d'une autre et des bogues inattendus dans l'interface.
Histoire
Lors du retour d'un objet par valeur d'une fonction dans l'un des systèmes de stockage internes de mots de passe, les données étaient effacées lors de la destruction de l'objet temporaire (shallow copy), ce qui faisait que l'objet réel contenait un pointeur nul, et la fuite a été découverte par hasard lors d'un audit de sécurité.