Duplicate possible:
Quelle est la différence entre une copie profonde et une copie superficielle?
Quelle est la différence entre une copie profonde et une copie superficielle. Quel type de copie un constructeur de copie fait-il?
Copie peu profonde:
Certains membres de la copie peuvent référencer les mêmes objets que l'original:
class X
{
private:
int i;
int *pi;
public:
X()
: pi(new int)
{ }
X(const X& copy) // <-- copy ctor
: i(copy.i), pi(copy.pi)
{ }
};
Ici, le membre pi
de l'original et l'objet copié X
désignera tous deux le même objet int
.
copie profonde:
Tous les membres de l'original sont clonés (de manière récursive, si nécessaire). Il n'y a pas d'objets partagés:
class X
{
private:
int i;
int *pi;
public:
X()
: pi(new int)
{ }
X(const X& copy) // <-- copy ctor
: i(copy.i), pi(new int(*copy.pi)) // <-- note this line in particular!
{ }
};
Ici, le membre pi
de l'objet X
original et copié pointera vers différents objets int
, mais les deux ont la même valeur.
Le constructeur de copie par défaut (fourni automatiquement si vous n'en fournissez pas vous-même) crée uniquement des copies superficielles.
Correction: Plusieurs commentaires ci-dessous ont fait remarquer à juste titre qu'il est faux de dire que le constructeur de copie par défaut effectue toujours une copie superficielle. (ou une copie profonde, d'ailleurs). Que le constructeur de copie d'un type crée une copie superficielle ou profonde, ou quelque chose entre les deux, dépend de la combinaison du comportement de chaque membre en matière de copie; Le constructeur de copie d'un type de membre peut être amené à faire ce qu'il veut, après tout.
Voici ce que dit la section 12.8, paragraphe 8 de la norme C++ de 1998 à propos des exemples de code ci-dessus:
Le constructeur de copie défini implicitement pour la classe
X
effectue une copie membre de ses sous-objets. [...] Chaque sous-objet est copié de la manière appropriée à son type: [...] [I] Si le sous-objet est de type scalaire, l'opérateur d'affectation intégré est utilisé.
L'exemple le plus représentatif est un tableau de pointeurs vers des structures ou des objets (qui sont mutables).
Une copie superficielle copie le tableau et conserve les références aux objets d'origine.
Une copie en profondeur copiera (clonera) également les objets afin qu'ils ne soient pas liés à l'original. Cela implique que les objets eux-mêmes sont copiés en profondeur. C’est là que les choses se compliquent car il n’existe aucun moyen de savoir si quelque chose a été copié en profondeur ou non.
Le constructeur de copie est utilisé pour initier le nouvel objet avec l'objet précédemment créé de la même classe. Par défaut, le compilateur a écrit une copie superficielle. La copie superficielle fonctionne bien lorsque l'allocation de mémoire dynamique n'est pas impliquée, car les deux objets pointent vers le même emplacement de mémoire dans un segment. Par conséquent, pour éliminer ce problème, nous avons écrit une copie complète afin que les deux objets possèdent leur propre copie d'attributs. dans un souvenir.
Afin de lire les détails avec des exemples complets et des explications, vous pouvez voir l'article Constructeurs et destructeurs .
Le constructeur de copie par défaut est superficiel. Vous pouvez créer vos propres constructeurs de copie profonds ou peu profonds, selon le cas. Voir Notes C++: OOP: Constructeurs de copie .
La copie profonde effectue littéralement une copie profonde. Cela signifie que si votre classe a des champs qui sont des références, leurs valeurs seront copiées, pas des références elles-mêmes. Si, par exemple, vous avez deux instances d'une classe, A & B avec des champs de type référence, et effectuez une copie en profondeur, la modification d'une valeur de ce champ dans A n'affectera pas une valeur dans B. Et vice-versa. Les choses sont différentes avec une copie superficielle, car seules les références sont copiées. Par conséquent, modifier ce champ dans un objet copié aurait une incidence sur l'objet d'origine.
Quel type de copie un constructeur de copie fait-il?
Cela dépend de la mise en œuvre. Cela signifie qu'il n'y a pas de règles strictes à ce sujet, vous pouvez l'implémenter comme une copie profonde ou une copie superficielle, mais pour autant que je sache, il est courant d'implémenter une copie profonde dans un constructeur de copie. Un constructeur de copie par défaut effectue cependant une copie superficielle.