Contenu du cours
C++ Oop
C++ Oop
Constructeurs de Copie
Il existe deux constructeurs spécialisés : le Constructeur de Copie et le Constructeur de Déplacement. Comprendre ces constructeurs est crucial pour une gestion efficace des ressources, l'allocation de mémoire et la manipulation des objets.
Constructeur de Copie
Lors de la copie de deux variables de type primitif, le processus est simple et ne nécessite généralement pas de considération particulière. Cependant, copier des objets est une tâche plus complexe et délicate. La distinction entre copie superficielle et copie profonde deviendra claire lorsque vous examinerez le code suivant :
main
#include <iostream> class Example { public: // Constructor that initializes p_data with a new integer value Example(int data) : p_data(new int(data)) { } // Destructor that prints the value of p_data and deallocates memory ~Example() { std::cout << *p_data << std::endl; delete p_data; } int* p_data; // Pointer to an integer }; int main() { Example obj1(25); // Creating an object with an initial value of 25 Example obj2(obj1); // Creating a second object using the obj1 *obj2.p_data = 1000; // Modifying the value of by p_data in the obj2 }
Remarque
Cela génère erreur :
free(): double free detected
Remarque
C'est précisément pourquoi un constructeur de copie est essentiel. Il nous permet d'effectuer une copie profonde, assurant la sécurité dans le processus.
Syntaxe du Constructeur de Copie
Créer un constructeur de copie partage certaines similitudes avec la création d'un constructeur, mais il a ses propres caractéristiques distinctives. L'approche générale pour créer un constructeur de copie comme d'habitude est décrite ci-dessous :
- Nom : le constructeur de copie porte le même nom que la classe. Il n'a pas de préfixe ou de symbole unique pour le différencier du constructeur régulier.
- Type de Paramètre : il prend un seul paramètre, généralement une référence à un objet constant de la même classe.
- Pas de Type de Retour : similaire aux autres constructeurs et au destructeur, le constructeur de copie n'a pas de type de retour, même pas void.
- Utilisation Spéciale : il est appelé automatiquement par le compilateur dans des scénarios spécifiques, tels que lorsqu'un objet est passé par valeur à une fonction, retourné d'une fonction, ou initialisé en utilisant un autre objet de la même classe.
main
#include <iostream> class Example { public: // Constructor that initializes p_data with a new integer value Example(int data) : p_data(new int(data)) { } // Copy constructor that performs deep copy of the Example object Example(const Example& other) : p_data(new int(*other.p_data)) { } // Destructor that prints the value pointed to by p_data and deallocates memory ~Example() { std::cout << *p_data << std::endl; delete p_data; } int* p_data; // Pointer to an integer }; int main() { Example first_obj(25); // Creating an Example object with an initial value of 25 Example second_obj(first_obj); // Creating a obj2 using obj1 *second_obj.p_data = 1000; // Modifying the value pointed }
La règle des trois
Il existe une directive pour les classes qui gèrent la mémoire allouée dynamiquement ou d'autres ressources. Elle stipule que si elle doit fournir une implémentation personnalisée pour l'une des trois méthodes suivantes :
- Destructeur (
~Example()
). - Constructeur de copie (
Example(const Example&)
). - Opérateur d'affectation par copie (
Example& operator=(const Example&)
).
Ensuite, il est souvent nécessaire de fournir des implémentations pour les trois. Cela est dû au fait que si une classe gère des ressources nécessitant un nettoyage ou un comportement de copie personnalisé, les implémentations par défaut fournies par le compilateur peuvent ne pas convenir.
1. Quel est le but d'un constructeur de copie ?
2. Laquelle des propositions suivantes décrit une copie profonde ?
Merci pour vos commentaires !