Quelle est la différence entre une copie profonde et une copie peu profonde?
Quelle est la différence entre une copie profonde et une copie peu profonde?
Réponses:
Les copies superficielles dupliquent le moins possible. Une copie superficielle d'une collection est une copie de la structure de la collection, pas des éléments. Avec une copie superficielle, deux collections partagent désormais les éléments individuels.
Les copies profondes reproduisent tout. Une copie complète d'une collection est constituée de deux collections avec tous les éléments de la collection d'origine dupliqués.
Largeur vs profondeur; pensez en termes d'arbre de références avec votre objet comme nœud racine.
Peu profond:
Les variables A et B se réfèrent à différentes zones de mémoire, lorsque B est affecté à A, les deux variables se réfèrent à la même zone de mémoire. Les modifications ultérieures du contenu de l'un ou de l'autre se reflètent instantanément dans le contenu de l'autre, car elles partagent le contenu.
Profond:
Les variables A et B font référence à différentes zones de mémoire, lorsque B est affecté à A, les valeurs de la zone de mémoire vers lesquelles A pointe sont copiées dans la zone de mémoire vers laquelle B pointe. Les modifications ultérieures du contenu de l'un ou l'autre restent propres à A ou B; le contenu n'est pas partagé.
En bref, cela dépend de ce qui indique quoi. Dans une copie superficielle, l'objet B pointe vers l'emplacement de l'objet A en mémoire. En copie profonde, tout ce qui se trouve dans l'emplacement de mémoire de l'objet A est copié dans l'emplacement de mémoire de l'objet B.
Cet article wiki a un grand diagramme.
Essayez de considérer l'image suivante
Par exemple, Object.MemberwiseClone crée un lien de copie superficiel
et en utilisant l' interface ICloneable , vous pouvez obtenir une copie complète comme décrit ici
Surtout pour les développeurs iOS:
Si B
est une copie superficielle de A
, alors pour les données primitives c'est comme B = [A assign];
et pour les objets c'est comme B = [A retain]
;
B et A pointent vers le même emplacement mémoire
Si B
c'est une copie complète de A
, alors c'est commeB = [A copy];
B et A pointent vers des emplacements de mémoire différents
L'adresse mémoire B est la même que celle de A
B a le même contenu que les A
Copie superficielle: copie les valeurs des membres d'un objet dans un autre.
Deep Copy: copie les valeurs des membres d'un objet dans un autre.
Tous les objets pointeurs sont dupliqués et copiés en profondeur.
Exemple:
class String
{
int size;
char* data;
};
String s1("Ace"); // s1.size = 3 s1.data=0x0000F000
String s2 = shallowCopy(s1);
// s2.size =3 s2.data = 0X0000F000
String s3 = deepCopy(s1);
// s3.size =3 s3.data = 0x0000F00F
// (With Ace copied to this location.)
Je n'ai pas vu de réponse courte et facile à comprendre ici - je vais donc essayer.
Avec une copie superficielle, tout objet pointé par la source est également pointé par la destination (afin qu'aucun objet référencé ne soit copié).
Avec une copie complète, tout objet pointé par la source est copié et la copie est pointée par la destination (il y aura donc maintenant 2 de chaque objet référencé). Cela revient dans l'arborescence des objets.
Par souci de simplicité, vous pouvez suivre cet article: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
Copie superficielle:
Copie profonde:
{Imaginez deux objets: A et B de même type _t (par rapport à C ++) et vous songez à copier de façon superficielle / profonde A vers B}
Copie peu profonde: fait simplement une copie de la référence à A dans B. Considérez-la comme une copie de l'adresse de A. Ainsi, les adresses de A et B seront les mêmes, c'est-à-dire qu'elles pointeront vers le même emplacement de mémoire, c'est-à-dire le contenu des données.
Copie profonde: fait simplement une copie de tous les membres de A, alloue de la mémoire dans un emplacement différent pour B, puis attribue les membres copiés à B pour obtenir une copie profonde. De cette façon, si A devient inexistant, B est toujours valide dans la mémoire. Le terme correct à utiliser serait le clonage, où vous savez qu'ils sont tous deux identiques, mais pourtant différents (c'est-à-dire stockés comme deux entités différentes dans l'espace mémoire). Vous pouvez également fournir votre wrapper de clone où vous pouvez décider via la liste d'inclusion / exclusion quelles propriétés sélectionner pendant la copie complète. C'est une pratique assez courante lorsque vous créez des API.
Vous pouvez choisir de faire une copie superficielle UNIQUEMENT si vous comprenez les enjeux impliqués. Lorsque vous avez un nombre énorme de pointeurs à gérer en C ++ ou C, faire une copie superficielle d'un objet est VRAIMENT une mauvaise idée.
EXAMPLE_OF_DEEP COPY_ Par exemple, lorsque vous essayez de faire un traitement d'image et une reconnaissance d'objet, vous devez masquer les "mouvements non pertinents et répétitifs" hors de vos zones de traitement. Si vous utilisez des pointeurs d'image, vous pourriez avoir la spécification pour enregistrer ces images de masque. MAINTENANT ... si vous faites une copie superficielle de l'image, lorsque les références de pointeur sont TUÉES de la pile, vous avez perdu la référence et sa copie, c'est-à-dire qu'il y aura une erreur d'exécution de violation d'accès à un moment donné. Dans ce cas, vous avez besoin d'une copie complète de votre image en la clonant. De cette façon, vous pouvez récupérer les masques au cas où vous en auriez besoin à l'avenir.
EXAMPLE_OF_SHALLOW_COPY Je ne suis pas très bien informé par rapport aux utilisateurs de StackOverflow alors n'hésitez pas à supprimer cette partie et à mettre un bon exemple si vous pouvez clarifier. Mais je pense vraiment que ce n'est pas une bonne idée de faire une copie superficielle si vous savez que votre programme va fonctionner pendant une période de temps infinie, c'est-à-dire une opération "push-pop" continue sur la pile avec des appels de fonction. Si vous démontrez quelque chose à une personne amateur ou novice (par exemple, des trucs de tutoriel C / C ++), alors ça va probablement. Mais si vous exécutez une application telle que le système de surveillance et de détection ou le système de suivi du sonar, vous n'êtes pas censé continuer à copier vos objets en profondeur car cela tuera votre programme tôt ou tard.
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
«ShallowCopy» pointe vers le même emplacement en mémoire que «Source». 'DeepCopy' pointe vers un emplacement différent dans la mémoire, mais le contenu est le même.
Qu'est-ce que la copie superficielle?
La copie superficielle est une copie bit à bit d'un objet. Un nouvel objet est créé qui a une copie exacte des valeurs de l'objet d'origine. Si l'un des champs de l'objet fait référence à d'autres objets, seules les adresses de référence sont copiées, c'est-à-dire que seule l'adresse mémoire est copiée.
Dans cette figure, les MainObject1
champs ont field1
de type int et ContainObject1
de type ContainObject
. Lorsque vous effectuez une copie superficielle de MainObject1
, MainObject2
est créé avec field2
contenant la valeur copiée de field1
et pointant toujours vers ContainObject1
lui-même. Notez que puisque field1
est de type primitif, sa valeur est copiée field2
mais comme ContainedObject1
c'est un objet, MainObject2
pointe toujours vers ContainObject1
. Ainsi, toutes les modifications apportées à ContainObject1
in MainObject1
seront reflétées dans MainObject2
.
Maintenant, s'il s'agit d'une copie superficielle, voyons ce qu'est une copie profonde?
Qu'est-ce que Deep Copy?
Une copie complète copie tous les champs et crée des copies de la mémoire allouée dynamiquement pointées par les champs. Une copie complète se produit lorsqu'un objet est copié avec les objets auxquels il se réfère.
Dans cette figure, le MainObject1 a des champs field1
de type int et ContainObject1
de type ContainObject
. Lorsque vous effectuez une copie complète de MainObject1
, MainObject2
est créé avec field2
contenant la valeur copiée de field1
et ContainObject2
contenant la valeur copiée de ContainObject1
. Notez que toute modification apportée à ContainObject1
in MainObject1
ne sera pas reflétée dans MainObject2
.
field3
qui, lorsqu'il est en mesure d'essayer de comprendre quelque chose d'aussi profond que ce problème, où se situe le n ° 3 dans cet exemple ContainObject2
?
Dans la programmation orientée objet, un type comprend une collection de champs membres. Ces champs peuvent être stockés soit par valeur, soit par référence (c'est-à-dire un pointeur vers une valeur).
Dans une copie superficielle, une nouvelle instance du type est créée et les valeurs sont copiées dans la nouvelle instance. Les pointeurs de référence sont également copiés tout comme les valeurs. Par conséquent, les références pointent vers les objets d'origine. Toutes les modifications apportées aux membres stockés par référence apparaissent à la fois dans l'original et dans la copie, car aucune copie n'a été effectuée de l'objet référencé.
Dans une copie complète, les champs qui sont stockés par valeur sont copiés comme précédemment, mais les pointeurs vers des objets stockés par référence ne sont pas copiés. Au lieu de cela, une copie complète est faite de l'objet référencé et un pointeur vers le nouvel objet est stocké. Toute modification apportée à ces objets référencés n'affectera pas les autres copies de l'objet.
«ShallowCopy» pointe vers le même emplacement en mémoire que «Source». 'DeepCopy' pointe vers un emplacement différent dans la mémoire, mais le contenu est le même.
Clonage peu profond:
Définition: "Une copie superficielle d'un objet copie l'objet" principal ", mais ne copie pas les objets internes." Lorsqu'un objet personnalisé (par exemple, un employé) n'a que des variables de type chaîne primitives, vous utilisez le clonage superficiel.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Vous revenez super.clone();
dans la méthode clone () substituée et votre travail est terminé.
Clonage profond :
Définition: "Contrairement à la copie superficielle, une copie profonde est une copie entièrement indépendante d'un objet."
Signifie lorsqu'un objet Employee contient un autre objet personnalisé:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Ensuite, vous devez également écrire le code pour cloner l'objet 'Adresse' dans la méthode clone () substituée. Sinon, l'objet Address ne sera pas cloné et il provoquera un bogue lorsque vous modifiez la valeur de Address dans l'objet Employee cloné, qui reflète également l'original.
var source = { firstName="Jane", lastname="Jones" };
var shallow = ShallowCopyOf(source);
var deep = DeepCopyOf(source);
source.lastName = "Smith";
WriteLine(source.lastName); // prints Smith
WriteLine(shallow.lastName); // prints Smith
WriteLine(deep.lastName); // prints Jones
Copie profonde
Une copie complète copie tous les champs et crée des copies de la mémoire allouée dynamiquement pointées par les champs. Une copie complète se produit lorsqu'un objet est copié avec les objets auxquels il se réfère.
Copie superficielle
La copie superficielle est une copie bit à bit d'un objet. Un nouvel objet est créé qui a une copie exacte des valeurs de l'objet d'origine. Si l'un des champs de l'objet fait référence à d'autres objets, seules les adresses de référence sont copiées, c'est-à-dire que seule l'adresse mémoire est copiée.
Copie superficielle - La variable de référence à l'intérieur des objets originaux et copiés peu profonds fait référence à un objet commun .
Copie profonde - La variable de référence à l'intérieur des objets originaux et copiés en profondeur fait référence à un objet différent .
clone fait toujours une copie superficielle.
public class Language implements Cloneable{
String name;
public Language(String name){
this.name=name;
}
public String getName() {
return name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
la classe principale suit-
public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{
ArrayList<Language> list=new ArrayList<Language>();
list.add(new Language("C"));
list.add(new Language("JAVA"));
ArrayList<Language> shallow=(ArrayList<Language>) list.clone();
//We used here clone since this always shallow copied.
System.out.println(list==shallow);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==shallow.get(i));//true
ArrayList<Language> deep=new ArrayList<Language>();
for(Language language:list){
deep.add((Language) language.clone());
}
System.out.println(list==deep);
for(int i=0;i<list.size();i++)
System.out.println(list.get(i)==deep.get(i));//false
}
Les résultats ci-dessus seront-
faux vrai vrai
faux faux faux
Tout changement apporté à un objet d'origine se reflétera dans un objet peu profond et non dans un objet profond.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
Output- Visualbasic C
Je voudrais donner un exemple plutôt que la définition formelle.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
Ce code montre une copie superficielle :
var copyObject1 = originalObject;
console.log(copyObject1.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject1.a = 4;
console.log(copyObject1.a); //now it will print 4
console.log(originalObject.a); // now it will also print 4
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // now it will print 1
Ce code montre une copie complète :
var copyObject2 = Object.assign({}, originalObject);
console.log(copyObject2.a); // it will print 1
console.log(originalObject.a); // it will also print 1
copyObject2.a = 4;
console.log(copyObject2.a); // now it will print 4
console.log(originalObject.a); // !! now it will print 1 !!
1 1 4 4 4 4 4 4
En termes simples, une copie superficielle est similaire à l'appel par référence et une copie approfondie est similaire à l'appel par valeur
Dans Appel par référence, les paramètres formels et réels d'une fonction font référence au même emplacement de mémoire et à la valeur.
Dans Appel par valeur, les paramètres formels et réels d'une fonction font référence à un emplacement de mémoire différent mais ayant la même valeur.
Une copie superficielle construit un nouvel objet composé et y insère ses références à l'objet d'origine.
Contrairement à la copie superficielle, la copie profonde construit un nouvel objet composé et insère également des copies des objets d'origine de l'objet composé d'origine.
Prenons un exemple.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
Le code ci-dessus imprime FAUX.
Voyons comment.
Objet composé d'origine x=[1,[2]]
(appelé composé car il contient un objet à l'intérieur de l'objet (Inception))
comme vous pouvez le voir sur l'image, il y a une liste à l'intérieur de la liste.
Ensuite, nous en créons une copie superficielle à l'aide de y = copy.copy(x)
. Ce que python fait ici, c'est qu'il créera un nouvel objet composé, mais les objets à l'intérieur d'eux pointent vers les objets d'origine.
Dans l'image, il a créé une nouvelle copie pour la liste externe. mais la liste intérieure reste la même que celle d'origine.
Nous en créons maintenant une copie profonde à l'aide de z = copy.deepcopy(x)
. ce que python fait ici, c'est qu'il créera un nouvel objet pour la liste externe ainsi que la liste interne. comme indiqué dans l'image ci-dessous (surligné en rouge).
À la fin, le code s'imprime False
, car y et z ne sont pas les mêmes objets.
HTH.
La copie superficielle crée un nouvel objet, puis copie les champs non statiques de l'objet actuel vers le nouvel objet. Si un champ est un type de valeur -> une copie bit par bit du champ est effectuée; pour un type de référence -> la référence est copiée mais l'objet référencé ne l'est pas; par conséquent, l'objet d'origine et son clone font référence au même objet.
La copie profonde crée un nouvel objet, puis copie les champs non statiques de l'objet actuel vers le nouvel objet. Si un champ est un type de valeur -> une copie bit par bit du champ est effectuée. Si un champ est un type de référence -> une nouvelle copie de l'objet référencé est effectuée. Les classes à cloner doivent être marquées comme [Sérialisable].
Tiré de [blog]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
La copie profonde implique l'utilisation du contenu d'un objet pour créer une autre instance de la même classe. Dans une copie complète, les deux objets peuvent contenir les mêmes informations mais l'objet cible aura ses propres tampons et ressources. la destruction de l'un ou l'autre objet n'affectera pas l'objet restant. L'opérateur d'affectation surchargé créerait une copie complète des objets.
La copie superficielle implique la copie du contenu d'un objet dans une autre instance de la même classe, créant ainsi une image miroir. En raison de la copie directe des références et des pointeurs, les deux objets partageront le même contenu contenu en externe de l'autre objet pour être imprévisible.
Explication:
En utilisant un constructeur de copie, nous copions simplement les valeurs de données membre par membre. Cette méthode de copie est appelée copie superficielle. Si l'objet est une classe simple, composée de types intégrés et sans pointeurs, cela serait acceptable. Cette fonction utiliserait les valeurs et les objets et son comportement ne serait pas modifié avec une copie superficielle, seules les adresses des pointeurs qui sont membres sont copiées et non la valeur vers laquelle pointe l'adresse. Les valeurs de données de l'objet seraient alors modifiées par inadvertance par la fonction. Lorsque la fonction sort de la portée, la copie de l'objet avec toutes ses données est extraite de la pile.
Si l'objet a des pointeurs, une copie complète doit être exécutée. Avec la copie en profondeur d'un objet, la mémoire est allouée à l'objet en magasin gratuit et les éléments pointés sont copiés. Une copie complète est utilisée pour les objets renvoyés par une fonction.
Pour ajouter plus à d'autres réponses,
La copie superficielle ne créera pas de nouvelle référence mais la copie profonde créera la nouvelle référence.
Voici le programme pour expliquer la copie profonde et peu profonde.
public class DeepAndShollowCopy {
int id;
String name;
List<String> testlist = new ArrayList<>();
/*
// To performing Shallow Copy
// Note: Here we are not creating any references.
public DeepAndShollowCopy(int id, String name, List<String>testlist)
{
System.out.println("Shallow Copy for Object initialization");
this.id = id;
this.name = name;
this.testlist = testlist;
}
*/
// To performing Deep Copy
// Note: Here we are creating one references( Al arraylist object ).
public DeepAndShollowCopy(int id, String name, List<String> testlist) {
System.out.println("Deep Copy for Object initialization");
this.id = id;
this.name = name;
String item;
List<String> Al = new ArrayList<>();
Iterator<String> itr = testlist.iterator();
while (itr.hasNext()) {
item = itr.next();
Al.add(item);
}
this.testlist = Al;
}
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("Java");
list.add("Oracle");
list.add("C++");
DeepAndShollowCopy copy=new DeepAndShollowCopy(10,"Testing", list);
System.out.println(copy.toString());
}
@Override
public String toString() {
return "DeepAndShollowCopy [id=" + id + ", name=" + name + ", testlist=" + testlist + "]";
}
}
Copier des araries:
Array est une classe, ce qui signifie qu'il s'agit d'un type de référence, donc array1 = array2 entraîne deux variables qui référencent le même tableau.
Mais regardez cet exemple:
static void Main()
{
int[] arr1 = new int[] { 1, 2, 3, 4, 5 };
int[] arr2 = new int[] { 6, 7, 8, 9, 0 };
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = arr1;
Console.WriteLine(arr1[2] + " " + arr2[2]);
arr2 = (int[])arr1.Clone();
arr1[2] = 12;
Console.WriteLine(arr1[2] + " " + arr2[2]);
}
clone superficiel signifie que seule la mémoire représentée par le tableau cloné est copiée.
Si le tableau contient des objets de type valeur, les valeurs sont copiées ;
si le tableau contient un type de référence, seules les références sont copiées. Par conséquent, il existe deux tableaux dont les membres font référence aux mêmes objets .
Pour créer une copie complète - où le type de référence est dupliqué, vous devez parcourir le tableau et cloner chaque élément manuellement.
private void button1_Click(object sender, EventArgs e) { int[] arr1 = new int[]{1,2,3,4,5}; int[] arr2 = new int[]{6,7,8,9,0}; MessageBox.Show(arr1[2] + " " + arr2[2]); arr2 = arr1; MessageBox.Show(arr1[2] + " " + arr2[2]); arr1[2] = 12; MessageBox.Show(arr1[2] + " " + arr2[2]); }
Je suis venu à comprendre des lignes suivantes.
La copie superficielle copie les champs d' un type de valeur d' objet (int, float, bool) dans l'objet cible et les types de référence d'objet (chaîne, classe, etc.) sont copiés en tant que références dans l'objet cible. Dans cette référence, les types de référence pointeront vers l'emplacement mémoire de l'objet source.
La copie approfondie copie les types de valeur et de référence d'un objet dans une nouvelle copie complète des objets cibles. Cela signifie que les types de valeur et les types de référence se verront attribuer de nouveaux emplacements de mémoire.
Ajoutant à toutes les définitions ci-dessus, une copie approfondie de plus et la plus couramment utilisée, se trouve dans le constructeur de copie (ou opérateur d'affectation de surcharge) de la classe.
Copie superficielle -> est lorsque vous ne fournissez pas de constructeur de copie. Ici, seul l'objet est copié mais pas tous les membres de la classe sont copiés.
Copie profonde -> est lorsque vous avez décidé d'implémenter le constructeur de copie ou l'affectation de surcharge dans votre classe et permet de copier tous les membres de la classe.
MyClass& MyClass(const MyClass& obj) // copy constructor for MyClass
{
// write your code, to copy all the members and return the new object
}
MyClass& operator=(const MyClass& obj) // overloading assignment operator,
{
// write your code, to copy all the members and return the new object
}
Le constructeur de copie est utilisé pour initialiser 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 correctement lorsque l'allocation de mémoire dynamique n'est pas impliquée, car lorsque l'allocation de mémoire dynamique est impliquée, les deux objets pointeront vers le même emplacement de mémoire dans un tas.Par conséquent, pour supprimer ce problème, nous avons écrit une copie approfondie afin que les deux objets aient leur propre copie d'attributs dans une mémoire. Afin de lire les détails avec des exemples et des explications complets, vous pouvez voir l'article Constructeurs C ++ .