language-agnostic - shallow - deep copy javascript
¿Cuál es la diferencia entre una copia profunda y una copia superficial? (30)
¿Cuál es la diferencia entre una copia profunda y una copia superficial?
''ShallowCopy'' apunta a la misma ubicación en la memoria que ''Source''. ''DeepCopy'' apunta a una ubicación diferente en la memoria, pero el contenido es el mismo.
Agregando a todas las definiciones anteriores, una copia profunda más y más comúnmente utilizada, está en el constructor de copias (o oprador de asignación de sobrecarga) de la clase.
Copia superficial -> es cuando no está proporcionando el constructor de copia. Aquí, solo se copia el objeto, pero no todos los miembros de la clase se copian.
Copia profunda -> es cuando ha decidido implementar el constructor de copias o la asignación de sobrecarga en su clase y le permite copiar a todos los miembros de la clase.
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
}
Anchura vs Profundidad; piense en términos de un árbol de referencias con su objeto como nodo raíz.
Superficial:
Las variables A y B se refieren a diferentes áreas de la memoria, cuando B se asigna a A, las dos variables se refieren a la misma área de la memoria. Las modificaciones posteriores de los contenidos de cualquiera de ellas se reflejan instantáneamente en los contenidos de otros, ya que comparten contenidos.
Profundo:
Las variables A y B se refieren a diferentes áreas de la memoria, cuando B se asigna a A, los valores en el área de memoria a los que A apunta se copian en el área de memoria a la que B apunta. Las modificaciones posteriores de los contenidos de cualquiera de los dos permanecen exclusivas de A o B; Los contenidos no son compartidos.
Copia superficial: copia los valores de miembro de un objeto a otro.
Copia profunda: copia los valores de los miembros de un objeto a otro.
Cualquier objeto puntero está duplicado y copiado en profundidad.
Ejemplo:
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.)
Copiando ararys:
La matriz es una clase, lo que significa que es un tipo de referencia, de modo que array1 = array2 da como resultado dos variables que hacen referencia a la misma matriz.
Pero mira este ejemplo:
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]);
}
clonación superficial significa que solo se copia la memoria representada por la matriz clonada.
Si la matriz contiene objetos de tipo de valor, los valores se copian ;
Si la matriz contiene un tipo de referencia, solo se copian las referencias, por lo que hay dos matrices cuyos miembros hacen referencia a los mismos objetos .
Para crear una copia profunda, donde el tipo de referencia está duplicado, debe recorrer la matriz y clonar cada elemento manualmente.
Copias poco profundas se duplican lo menos posible. Una copia superficial de una colección es una copia de la estructura de la colección, no los elementos. Con una copia superficial, dos colecciones ahora comparten los elementos individuales.
Copias profundas duplican todo. Una copia profunda de una colección son dos colecciones con todos los elementos de la colección original duplicados.
El constructor de copia se utiliza para inicializar el nuevo objeto con el objeto creado anteriormente de la misma clase. Por defecto el compilador escribió una copia superficial. La copia superficial funciona bien cuando la asignación de memoria dinámica no está involucrada porque cuando se trata de una asignación de memoria dinámica, ambos objetos apuntarán hacia la misma ubicación de memoria en un montón. Por lo tanto, para eliminar este problema, escribimos una copia profunda para que ambos objetos tengan su propia copia de atributos. en un recuerdo. Para leer los detalles con ejemplos completos y explicaciones, puede ver los constructores del artículo C ++ .
En definitiva, depende de lo que apunte a qué. En una copia superficial, el objeto B apunta a la ubicación del objeto A en la memoria. En copia profunda, todas las cosas en la ubicación de memoria del objeto A se copian en la ubicación de memoria del objeto B.
Este artículo wiki tiene un gran diagrama.
En la programación orientada a objetos, un tipo incluye una colección de campos miembros. Estos campos se pueden almacenar por valor o por referencia (es decir, un puntero a un valor).
En una copia superficial, se crea una nueva instancia del tipo y los valores se copian en la nueva instancia. Los punteros de referencia también se copian al igual que los valores. Por lo tanto, las referencias apuntan a los objetos originales. Cualquier cambio en los miembros que se almacenan por referencia aparece tanto en el original como en la copia, ya que no se hizo ninguna copia del objeto referenciado.
En una copia profunda, los campos que se almacenan por valor se copian como antes, pero los punteros a los objetos almacenados por referencia no se copian. En su lugar, se hace una copia profunda del objeto referenciado y se almacena un puntero al nuevo objeto. Cualquier cambio que se realice en esos objetos referenciados no afectará otras copias del objeto.
En términos simples, una Copia superficial es similar a la llamada por referencia y una Copia profunda es similar a la llamada por valor
En Llamada por referencia, los parámetros tanto formales como reales de una función se refieren a la misma ubicación de memoria y al valor.
En Call By Value, tanto los parámetros formales como los reales de una función se refieren a una ubicación de memoria diferente pero que tienen el mismo valor.
Imagina que hay dos matrices llamadas arr1 y arr2.
arr1 = arr2; //shallow copy
arr1 = arr2.clone(); //deep copy
La copia superficial no creará una nueva referencia, pero la copia profunda creará la nueva referencia.
Aquí está el programa para explicar la copia profunda y superficial.
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 + "]";
}
}
Me gustaría dar ejemplo en lugar de la definición formal.
var originalObject = {
a : 1,
b : 2,
c : 3,
};
Este código muestra una copia superficial :
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
Este código muestra una copia profunda :
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 !!
No he visto una respuesta breve y fácil de entender aquí, así que lo intentaré.
Con una copia superficial, cualquier objeto apuntado por la fuente también es señalado por el destino (de modo que no se copian objetos referenciados).
Con una copia profunda, cualquier objeto apuntado por la fuente se copia y la copia es apuntada por el destino (por lo que ahora habrá 2 de cada objeto referenciado). Esto recurre hacia abajo en el árbol de objetos.
Para agregar más a otras respuestas,
- una Copia superficial de un objeto realiza copia por valor para propiedades basadas en tipos de valor, y copia por referencia para propiedades basadas en tipos de referencia.
- una copia profunda de un objeto realiza la copia por valor de las propiedades basadas en tipos de valor, así como la copia por valor de las propiedades basadas en tipos de referencia en la jerarquía (de tipos de referencia)
Para agregar solo un poco más de confusión entre la copia superficial y simplemente asignar un nuevo nombre de variable a la lista.
"Digamos que tenemos:
x = [
[1,2,3],
[4,5,6],
]
Esta declaración crea 3 listas: 2 listas internas y una lista externa. Una referencia a la lista externa está disponible bajo el nombre x. Si lo hacemos
y = x
No se copian datos. Todavía tenemos las mismas 3 listas en memoria en alguna parte. Todo esto hizo que la lista externa estuviera disponible bajo el nombre y, además de su nombre anterior x. Si lo hacemos
y = list(x)
o
y = x[:]
Esto crea una nueva lista con los mismos contenidos que x. La lista x contenía una referencia a las 2 listas internas, por lo que la nueva lista también contendrá una referencia a esas 2 listas internas. Sólo se copia una lista: la lista externa. Ahora hay 4 listas en la memoria, las dos listas internas, la lista externa y la copia de la lista externa. La lista externa original está disponible bajo el nombre x, y la nueva lista externa está disponible bajo el nombre y.
Las listas internas no han sido copiadas! ¡Puedes acceder y editar las listas internas desde x o y en este punto!
Si tiene una lista bidimensional (o superior), o cualquier tipo de estructura de datos anidada, y desea hacer una copia completa de todo, entonces desea utilizar la función deepcopy () en el módulo de copia. Su solución también funciona para las listas 2-D, ya que itera sobre los elementos de la lista externa y hace una copia de cada una de ellas, luego crea una nueva lista externa para todas las copias internas ".
Solo por entenderlo bien, puede seguir este artículo: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm
Copia superficial:
Copia profunda:
Tomado de [blog]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html
Copia profunda implica utilizar el contenido de un objeto para crear otra instancia de la misma clase. En una copia profunda, los dos objetos pueden contener su misma información, pero el objeto de destino tendrá sus propios búferes y recursos. la destrucción de cualquier objeto no afectará el objeto restante. El operador de asignación sobrecargado crearía una copia profunda de los objetos.
La copia superficial implica copiar el contenido de un objeto en otra instancia de la misma clase, creando así una imagen reflejada. Debido a la copia directa de referencias y punteros, los dos objetos compartirán el mismo contenido contenido externamente del otro objeto para que sea impredecible.
Explicación:
Usando un constructor de copia, simplemente copiamos los valores de datos miembro por miembro. Este método de copia se llama copia superficial. Si el objeto es una clase simple, compuesta de tipos integrados y sin punteros, esto sería aceptable. Esta función usaría los valores y los objetos y su comportamiento no se alteraría con una copia superficial, solo se copiarán las direcciones de los punteros que son miembros y no el valor al que la dirección apunta. Los valores de datos del objeto serían alterados inadvertidamente por la función. Cuando la función queda fuera del alcance, la copia del objeto con todos sus datos se extrae de la pila.
Si el objeto tiene algún puntero, se debe ejecutar una copia profunda. Con la copia en profundidad de un objeto, la memoria se asigna para el objeto en el almacén libre y se copian los elementos apuntados. Una copia profunda se utiliza para los objetos que se devuelven desde una función.
Trate de considerar la siguiente imagen
Por ejemplo, Object.MemberwiseClone crea un link copia superficial
y utilizando la interfaz de ICloneable , puede obtener una copia profunda como se describe here
Una copia superficial construye un nuevo objeto compuesto e inserta sus referencias en el objeto original.
A diferencia de la copia superficial, deepcopy construye un nuevo objeto compuesto y también inserta copias de los objetos originales del objeto original compuesto.
Tomemos un ejemplo.
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
El código anterior se imprime FALSO.
Veamos cómo.
Objeto compuesto original x=[1,[2]]
(llamado como compuesto porque tiene un objeto dentro del objeto (Inicio))
Como se puede ver en la imagen, hay una lista dentro de la lista.
Luego creamos una copia superficial de ella usando y = copy.copy(x)
. Lo que Python hace aquí es que creará un nuevo objeto compuesto, pero los objetos dentro de ellos apuntan a los objetos orignales.
En la imagen se ha creado una nueva copia para la lista externa. pero la lista interna sigue siendo la misma que la original.
Ahora creamos una copia en profundidad de ella usando z = copy.deepcopy(x)
. lo que Python hace aquí es que creará un nuevo objeto para la lista externa y para la lista interna. como se muestra en la imagen de abajo (rojo resaltado).
Al final, el código se imprime False
, ya que y y z no son los mismos objetos.
HTH.
{Imagine dos objetos: A y B del mismo tipo _t (con respecto a C ++) y está pensando en copiar de A a B de poca profundidad / en profundidad}
Copia superficial: Simplemente haga una copia de la referencia a A en B. Piense en ello como una copia de la dirección de A. Por lo tanto, las direcciones de A y B serán las mismas, es decir, apuntarán a la misma ubicación de memoria, es decir, el contenido de los datos.
Copia profunda: Simplemente hace una copia de todos los miembros de A, asigna memoria en una ubicación diferente para B y luego asigna los miembros copiados a B para lograr una copia profunda. De esta manera, si A deja de existir, B sigue siendo válido en la memoria. El término correcto a utilizar sería clonación, donde se sabe que ambos son totalmente iguales, pero aún así diferentes (es decir, almacenados como dos entidades diferentes en el espacio de la memoria). También puede proporcionar su contenedor de clones donde puede decidir a través de la lista de inclusión / exclusión qué propiedades seleccionar durante la copia en profundidad. Esta es una práctica bastante común cuando creas APIs.
Puede elegir hacer una Copia superficial SÓLO_IF si comprende las apuestas involucradas. Cuando tienes un gran número de punteros para tratar en C ++ o C, REALMENTE hacer una copia superficial de un objeto es REALMENTE una mala idea.
EXAMPLE_OF_DEEP COPY_ Un ejemplo es que, cuando intenta realizar el procesamiento de imágenes y el reconocimiento de objetos, necesita enmascarar "Movimiento irrelevante y repetitivo" fuera de sus áreas de procesamiento. Si está utilizando punteros de imagen, es posible que tenga la especificación para guardar esas imágenes de máscara. AHORA ... si hace una copia superficial de la imagen, cuando las referencias del puntero se MATAN de la pila, perderá la referencia y su copia, es decir, se producirá un error de infracción de acceso en tiempo de ejecución en algún momento. En este caso, lo que necesita es una copia profunda de su imagen CLONANDOLA. De esta forma, puede recuperar las máscaras en caso de que las necesite en el futuro.
EXAMPLE_OF_SHALLOW_COPY No tengo muchos conocimientos en comparación con los usuarios de , así que siéntase libre de eliminar esta parte y de poner un buen ejemplo si puede aclarar. Pero realmente creo que no es una buena idea hacer una copia superficial si sabe que su programa se ejecutará durante un período infinito de tiempo, es decir, una operación continua de "push-pop" sobre la pila con llamadas a funciones. Si está demostrando algo a una persona aficionada o principiante (por ejemplo, tutorial de C / C ++), entonces probablemente esté bien. Pero si está ejecutando una aplicación como el sistema de vigilancia y detección, o el Sistema de seguimiento de sonar, no debe seguir copiando sus objetos, ya que esto acabará con su programa tarde o temprano.
¿Qué es la copia superficial?
Copia superficial es una copia en bits de un objeto. Se crea un nuevo objeto que tiene una copia exacta de los valores en el objeto original. Si alguno de los campos del objeto son referencias a otros objetos, solo se copian las direcciones de referencia, es decir, solo se copia la dirección de la memoria.
En esta figura, MainObject1
tiene campos field1
de tipo int, y ContainObject1
de tipo ContainObject
. Cuando haces una copia superficial de MainObject1
, MainObject2
se crea con field2
contiene el valor copiado de field1
y sigue apuntando a ContainObject1
. Tenga en cuenta que dado que field1
es de tipo primitivo, su valor se copia en field2
pero como ContainedObject1
es un objeto, MainObject2
aún apunta a ContainObject1
. Por lo tanto, cualquier cambio realizado en ContainObject1
en MainObject1
se reflejará en MainObject2
.
Ahora bien, si esta es una copia superficial, veamos ¿qué es una copia profunda?
¿Qué es Deep Copy?
Una copia profunda copia todos los campos y hace copias de la memoria asignada dinámicamente a las que apuntan los campos. Una copia profunda se produce cuando un objeto se copia junto con los objetos a los que se refiere.
En esta figura, el MainObject1 tiene campos field1
de tipo int y ContainObject1
de tipo ContainObject
. Cuando hace una copia MainObject1
de MainObject1
, MainObject2
se crea con field2
contiene el valor copiado de field1
y ContainObject2
contiene el valor copiado de ContainObject1
. Tenga en cuenta que los cambios realizados en ContainObject1
en MainObject1
no se reflejarán en MainObject2
.
Clonación superficial:
Definición: "Una copia superficial de un objeto copia el objeto ''principal'', pero no copia los objetos internos". Cuando un objeto personalizado (p. Ej., Empleado) tiene solo variables primitivas de tipo Cadena, se usa la Clonación superficial.
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
super.clone();
en el método clone () invalidado y su trabajo ha terminado.
Clonación profunda :
Definición: "A diferencia de la copia superficial, una copia profunda es una copia totalmente independiente de un objeto".
Significa cuando un objeto Empleado contiene otro objeto personalizado:
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
Luego, debe escribir el código para clonar el objeto ''Dirección'' y también en el método clone () invalidado. De lo contrario, el objeto Dirección no se clonará y causará un error al cambiar el valor de la Dirección en el objeto Empleado clonado, que también refleja el original.
Copia profunda
Una copia profunda copia todos los campos y hace copias de la memoria asignada dinámicamente a las que apuntan los campos. Una copia profunda se produce cuando un objeto se copia junto con los objetos a los que se refiere.
Copia superficial
Copia superficial es una copia en bits de un objeto. Se crea un nuevo objeto que tiene una copia exacta de los valores en el objeto original. Si alguno de los campos del objeto son referencias a otros objetos, solo se copian las direcciones de referencia, es decir, solo se copia la dirección de la memoria.
Copia superficial : la variable de referencia dentro de los objetos originales y copiados poco profundos tiene referencia a un objeto común .
Copia profunda : la variable de referencia dentro de los objetos originales y copiados en profundidad tiene referencias a objetos diferentes .
clon siempre hace copia superficial.
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();
}
}
clase principal es siguiente-
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
}
El resultado de lo anterior será
falso verdadero verdadero
falso falso falso
Cualquier cambio realizado en el objeto original se reflejará en un objeto superficial y no en un objeto profundo.
list.get(0).name="ViSuaLBaSiC";
System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName());
OutPut- ViSuaLBaSiC C
Especialmente para desarrolladores de iOS:
Si B
es una copia superficial de A
, entonces para datos primitivos es como B = [A assign];
y para los objetos es como B = [A retain]
;
B y A apuntan a la misma ubicación de memoria
Si B
es una copia profunda de A
, entonces es como B = [A copy];
B y A apuntan a diferentes ubicaciones de memoria
La dirección de memoria B es la misma que la de A
B tiene los mismos contenidos que A
La copia superficial es crear un nuevo objeto y luego copiar los campos no estáticos del objeto actual al nuevo objeto. Si un campo es un tipo de valor -> se realiza una copia bit a bit del campo; para un tipo de referencia -> la referencia se copia pero el objeto referido no; por lo tanto, el objeto original y su clon se refieren al mismo objeto.
Copia profunda es crear un nuevo objeto y luego copiar los campos no estáticos del objeto actual al nuevo objeto. Si un campo es un tipo de valor -> se realiza una copia bit a bit del campo. Si un campo es un tipo de referencia -> se realiza una nueva copia del objeto referido. Las clases que se clonarán deben marcarse como [Serializable].
char * Source = "Hello, world.";
char * ShallowCopy = Source;
char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);
''ShallowCopy'' apunta a la misma ubicación en la memoria que ''Source''. ''DeepCopy'' apunta a una ubicación diferente en la memoria, pero el contenido es el mismo.
struct sample
{
char * ptr;
}
void shallowcpy(sample & dest, sample & src)
{
dest.ptr=src.ptr;
}
void deepcpy(sample & dest, sample & src)
{
dest.ptr=malloc(strlen(src.ptr)+1);
memcpy(dest.ptr,src.ptr);
}
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