Qual é a diferença entre uma cópia detalhada e uma cópia superficial?

Qual é a diferença entre uma cópia detalhada e uma cópia superficial?

As cópias rasas duplicam o mínimo possível. Uma cópia superficial de uma coleção é uma cópia da estrutura da coleção, não dos elementos. Com uma cópia superficial, duas collections agora compartilham os elementos individuais.

Cópias profundas duplicam tudo. Uma cópia profunda de uma coleção é duas collections com todos os elementos da coleção original duplicados.

Largura vs profundidade; pense em termos de uma tree de referências com o seu object como o nó raiz.

Raso:

Antes de copiarCópia SuperficialSuperficial feito

As variables ​​A e B referem-se a diferentes áreas da memory, quando B é atribuído a A, as duas variables ​​referem-se à mesma área de memory. Modificações posteriores no conteúdo de cada uma são instantaneamente refletidas no conteúdo de outras, pois compartilham o conteúdo.

Deep:

Antes de copiarCópia profundaBem feito

As variables ​​A e B referem-se a diferentes áreas de memory, quando B é atribuído a A, os valores na área de memory para os quais A aponta são copiados para a área de memory à qual B aponta. Modificações posteriores no conteúdo de qualquer um deles permanecem exclusivas de A ou B; o conteúdo não é compartilhado.

Em suma, depende do que aponta para o quê. Em uma cópia superficial, o object B aponta para o local do object A na memory. Na cópia profunda, todas as coisas na localização da memory do object A são copiadas para a localização da memory do object B.

Este artigo wiki tem um ótimo diagrama.

http://en.wikipedia.org/wiki/Object_copy

Especialmente para desenvolvedores iOS:

Se B é uma cópia superficial de A , então para dados primitivos é como B = [A assign]; e para objects é como B = [A retain] ;

B e A apontam para o mesmo local de memory

Se B é uma cópia profunda de A , então é como B = [A copy];

B e A apontam para locais de memory diferentes

O endereço de memory B é o mesmo que o de A

B tem o mesmo conteúdo de A

Cópia superficial: copia os valores dos membros de um object para outro.

Cópia profunda: copia os valores dos membros de um object para outro.
Todos os objects apontadores são duplicados e Deep Copied.

Exemplo:

 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.) 

Tente considerar a seguinte imagem

insira a descrição da imagem aqui

Por exemplo, Object.MemberwiseClone cria um link de cópia superficial

e usando a interface ICloneable você pode obter uma cópia detalhada como descrito aqui

Eu não vi uma resposta curta e fácil de entender aqui – então vou tentar.

Com uma cópia superficial, qualquer object apontado pela origem também é apontado pelo destino (para que nenhum object referenciado seja copiado).

Com uma cópia profunda, qualquer object apontado pela origem é copiado e a cópia é apontada pelo destino (então, haverá agora 2 de cada object referenciado). Isso recursiona a tree de objects.

{Imagine dois objects: A e B do mesmo tipo _t (com relação ao C ++) e você está pensando em copiar raso / profundo A para B}

Cópia superficial: Simplesmente faz uma cópia da referência para A em B. Pense nisso como uma cópia do endereço de A. Assim, os endereços de A e B serão os mesmos, ou seja, eles estarão apontando para o mesmo local de memory, ou seja, o conteúdo dos dados.

Cópia profunda: Simplesmente faz uma cópia de todos os membros de A, aloca memory em um local diferente para B e, em seguida, atribui os membros copiados a B para obter uma cópia profunda. Desta forma, se A se torna inexistente B ainda é válido na memory. O termo correto a ser usado seria clonagem, onde você sabe que ambos são totalmente iguais, mas ainda assim diferentes (isto é, armazenados como duas entidades diferentes no espaço da memory). Você também pode fornecer seu wrapper clone, onde você pode decidir, através da lista de inclusão / exclusão, quais propriedades selecionar durante a cópia detalhada. Essa é uma prática bastante comum quando você cria APIs.

Você pode optar por fazer uma Cópia Rasa ONLY_IF, você entende os riscos envolvidos. Quando você tem um número enorme de pointers para lidar em C ++ ou C, fazer uma cópia superficial de um object é MUITO uma má ideia.

EXAMPLE_OF_DEEP COPY_ Um exemplo é que, quando você está tentando fazer o processamento de imagens e o reconhecimento de objects, precisa mascarar “Movimentos irrelevantes e repetitivos” de suas áreas de processamento. Se você estiver usando pointers de imagem, poderá ter a especificação para salvar essas imagens de máscara. AGORA … se você fizer uma cópia superficial da imagem, quando as referências de ponteiro são KILLED da pilha, você perdeu a referência e sua cópia, ou seja, haverá um erro de tempo de execução da violação de access em algum momento. Nesse caso, o que você precisa é de uma cópia profunda da sua imagem CLONANDO. Desta forma, você pode recuperar as máscaras caso precise delas no futuro.

EXAMPLE_OF_SHALLOW_COPY Não sou extremamente experiente em comparação com os usuários do StackOverflow, portanto, sinta-se à vontade para excluir essa parte e dar um bom exemplo, se puder esclarecer. Mas eu realmente acho que não é uma boa idéia fazer uma cópia superficial se você souber que seu programa será executado por um período infinito de tempo, isto é, operação “push-pop” contínua sobre a pilha com chamadas de function. Se você está demonstrando algo para uma pessoa amadora ou iniciante (por exemplo, coisas de tutorial em C / C ++), então provavelmente está tudo bem. Mas se você estiver executando um aplicativo como o sistema de vigilância e detecção, ou o Sistema de Rastreamento Sonar, você não deve continuar copiando seus objects superficialmente porque isso matará seu programa mais cedo ou mais tarde.

Apenas por uma questão de fácil compreensão, você pode seguir este artigo: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm


Cópia superficial:

Cópia superficial


Cópia profunda:

Cópia profunda

 char * Source = "Hello, world."; char * ShallowCopy = Source; char * DeepCopy = new char(strlen(Source)+1); strcpy(DeepCopy,Source); 

‘ShallowCopy’ aponta para o mesmo local na memory que ‘Source’ faz. ‘DeepCopy’ aponta para um local diferente na memory, mas o conteúdo é o mesmo.

O que é a cópia superficial?

Cópia superficial é uma cópia bit-wise de um object. Um novo object é criado com uma cópia exata dos valores no object original. Se qualquer um dos campos do object são referências a outros objects, apenas os endereços de referência são copiados, ou seja, somente o endereço de memory é copiado. Cópia superficial

Nesta figura, o MainObject1 tem campos MainObject1 do tipo int e ContainObject1 do tipo ContainObject . Quando você faz uma cópia superficial de MainObject1 , MainObject2 é criado com o field2 contendo o valor copiado do field1 e ainda apontando para o próprio ContainObject1 . Observe que, como o field1 é do tipo primitivo, seu valor é copiado para o field2 mas como ContainedObject1 é um object, o MainObject2 ainda aponta para ContainObject1 . Portanto, quaisquer alterações feitas em ContainObject1 em MainObject1 serão refletidas em MainObject2 .

Agora, se esta é uma cópia superficial, vamos ver o que é uma cópia profunda?

O que é o Deep Copy?

Uma cópia profunda copia todos os campos e faz cópias da memory alocada dinamicamente apontada pelos campos. Uma cópia profunda ocorre quando um object é copiado junto com os objects aos quais ele se refere. Cópia profunda

Nesta figura, o MainObject1 tem campos field1 do tipo int e ContainObject1 do tipo ContainObject . Quando você faz uma cópia profunda de MainObject1 , MainObject2 é criado com o field2 contendo o valor copiado de ContainObject2 e ContainObject2 contendo o valor copiado de ContainObject1 . Observe que quaisquer alterações feitas em ContainObject1 no MainObject1 não serão refletidas no MainObject2 .

bom artigo

Na programação orientada a objects, um tipo inclui uma coleção de campos de membros. Esses campos podem ser armazenados por valor ou por referência (ou seja, um ponteiro para um valor).

Em uma cópia superficial, uma nova instância do tipo é criada e os valores são copiados para a nova instância. Os pointers de referência também são copiados como os valores. Portanto, as referências estão apontando para os objects originais. Quaisquer alterações nos membros armazenadas por referência aparecem no original e na cópia, uma vez que nenhuma cópia foi feita do object referenciado.

Em uma cópia profunda, os campos armazenados por valor são copiados como antes, mas os pointers para objects armazenados por referência não são copiados. Em vez disso, uma cópia profunda é feita do object referenciado e um ponteiro para o novo object é armazenado. Quaisquer alterações feitas nesses objects referenciados não afetarão outras cópias do object.

‘ShallowCopy’ aponta para o mesmo local na memory que ‘Source’ faz. ‘DeepCopy’ aponta para um local diferente na memory, mas o conteúdo é o mesmo.

 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 

Cópia Rasa – A variável de referência dentro dos objects originais e de cópia superficial tem referência ao object comum .

Cópia Profunda – Variável de referência dentro de objects originais e copiados em profundidade fazem referência a objects diferentes .

clone sempre faz cópia 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(); } } 

class principal é seguinte-

 public static void main(String args[]) throws ClassNotFoundException, CloneNotSupportedException{ ArrayList list=new ArrayList(); list.add(new Language("C")); list.add(new Language("JAVA")); ArrayList shallow=(ArrayList) list.clone(); //We used here clone since this always shallow copied. System.out.println(list==shallow); for(int i=0;i deep=new ArrayList(); for(Language language:list){ deep.add((Language) language.clone()); } System.out.println(list==deep); for(int i=0;i 

OutPut de cima será

falso verdadeiro

falso falso falso

Qualquer alteração feita no object original refletirá em object superficial que não esteja no object profundo.

  list.get(0).name="ViSuaLBaSiC"; System.out.println(shallow.get(0).getName()+" "+deep.get(0).getName()); 

OutPut- ViSuaLBaSiC C

Eu gostaria de dar um exemplo e não a definição formal.

 var originalObject = { a : 1, b : 2, c : 3, }; 

Este código mostra uma cópia 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 mostra uma cópia 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 !! 

Clonagem Superficial:
Definição: “Uma cópia superficial de um object copia o object ‘principal’, mas não copia os objects internos.” Quando um object personalizado (por exemplo, Employee) tem apenas variables ​​de tipo primitivo, String, você usa Clonagem Rasa.

 Employee e = new Employee(2, "john cena"); Employee e2=e.clone(); 

Você retorna super.clone(); no método clone () substituído e seu trabalho acabou.

Clonagem Profunda :
Definição: “Ao contrário da cópia superficial, uma cópia detalhada é uma cópia totalmente independente de um object.”
Significa quando um object Employee contém outro object personalizado:

 Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts"); 

Então você tem que escrever o código para clonar o object ‘Address’, bem como o método clone () substituído. Caso contrário, o object Address não será clonado e causará um bug quando você alterar o valor de Address no object Employee clonado, o que também reflete o original.

 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); } 

Em termos simples, uma cópia superficial é semelhante a chamada por referência e uma cópia profunda é semelhante a chamada pelo valor

Em chamada por referência, os parâmetros formais e reais de uma function referem-se a mesma localização de memory e o valor.

Em chamada por valor, os parâmetros formais e reais de uma function referem-se a localização de memory diferente, mas com o mesmo valor.

Imagine que há duas matrizes chamadas arr1 e arr2.

 arr1 = arr2; //shallow copy arr1 = arr2.clone(); //deep copy 

Cópia profunda

Uma cópia profunda copia todos os campos e faz cópias da memory alocada dinamicamente apontada pelos campos. Uma cópia profunda ocorre quando um object é copiado junto com os objects aos quais ele se refere.

Cópia superficial

Cópia superficial é uma cópia bit-wise de um object. Um novo object é criado com uma cópia exata dos valores no object original. Se qualquer um dos campos do object são referências a outros objects, apenas os endereços de referência são copiados, ou seja, apenas o endereço de memory é copiado.

Cópia profunda e exemplo de cópia superficial

Retirado de [blog]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Cópia profunda envolve o uso do conteúdo de um object para criar outra instância da mesma class. Em uma cópia profunda, os dois objects podem conter a mesma informação, mas o object de destino terá seus próprios buffers e resources. a destruição de qualquer object não afetará o object restante. O operador de atribuição sobrecarregado criaria uma cópia profunda de objects.

A cópia superficial envolve copiar o conteúdo de um object em outra instância da mesma class, criando assim uma imagem espelhada. Devido à cópia direta de referências e pointers, os dois objects compartilharão o mesmo conteúdo contido externamente do outro object como imprevisível.

Explicação:

Usando um construtor de cópia, simplesmente copiamos o membro de valores de dados por membro. Este método de cópia é chamado de cópia superficial. Se o object é uma class simples, composta de tipos internos e sem pointers, isso seria aceitável. Essa function usaria os valores e os objects e seu comportamento não seria alterado com uma cópia superficial, apenas os endereços dos pointers que são membros são copiados e não o valor para o qual o endereço está apontando. Os valores de dados do object seriam então inadvertidamente alterados pela function. Quando a function sai do escopo, a cópia do object com todos os seus dados é retirada da pilha.

Se o object tiver algum ponteiro, será necessário executar uma cópia profunda. Com a cópia profunda de um object, a memory é alocada para o object no armazenamento gratuito e os elementos apontados são copiados. Uma cópia profunda é usada para objects retornados de uma function.

Para adicionar mais a outras respostas,

  • uma Cópia Rasa de um object executa cópia por valor para propriedades baseadas em tipos de valor e copia por referência para propriedades baseadas em tipos de referência.
  • uma Cópia Profunda de um object realiza cópia por valor para propriedades baseadas em tipos de valor, bem como cópia por valor para propriedades baseadas em tipos de referência no fundo da hierarquia (de tipos de referência)

A cópia superficial não criará nova referência, mas a cópia profunda criará a nova referência.

Aqui está o programa para explicar a cópia profunda e superficial.

 public class DeepAndShollowCopy { int id; String name; List testlist = new ArrayList<>(); /* // To performing Shallow Copy // Note: Here we are not creating any references. public DeepAndShollowCopy(int id, String name, Listtestlist) { 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 testlist) { System.out.println("Deep Copy for Object initialization"); this.id = id; this.name = name; String item; List Al = new ArrayList<>(); Iterator itr = testlist.iterator(); while (itr.hasNext()) { item = itr.next(); Al.add(item); } this.testlist = Al; } public static void main(String[] args) { List 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 + "]"; } } 

Copiando ararys:

Array é uma class, o que significa que é um tipo de referência, então array1 = array2 resulta em duas variables ​​que fazem referência à mesma matriz.

Mas olhe este exemplo:

  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 superficial significa que apenas a memory representada pela matriz clonada é copiada.

Se a matriz contiver objects de tipo de valor, os valores serão copiados ;

se a matriz contiver o tipo de referência, somente as referências serão copiadas – assim, como resultado, há duas matrizes cujos membros fazem referência aos mesmos objects .

Para criar uma cópia profunda – onde o tipo de referência é duplicado, você deve percorrer a matriz e clonar cada elemento manualmente.

A cópia superficial está criando um novo object e copiando os campos não estáticos do object atual para o novo object. Se um campo é um tipo de valor -> uma cópia bit-a-bit do campo é executada; para um tipo de referência -> a referência é copiada, mas o object referido não é; portanto, o object original e seu clone se referem ao mesmo object.

A cópia profunda está criando um novo object e copiando os campos não estáticos do object atual para o novo object. Se um campo é um tipo de valor -> uma cópia bit a bit do campo é executada. Se um campo é um tipo de referência -> uma nova cópia do object referido é executada. As classs a serem clonadas devem ser marcadas como [Serializable].

Uma cópia superficial constrói um novo object composto e insere suas referências nele para o object original.

Ao contrário da cópia superficial, o deepcopy constrói um novo object composto e também insere cópias dos objects originais do object composto original.

Vamos dar um exemplo.

 import copy x =[1,[2]] y=copy.copy(x) z= copy.deepcopy(x) print(y is z) 

O código acima imprime FALSE.

Vamos ver como.

Objeto composto original x=[1,[2]] (chamado como composto porque possui object dentro do object (Inception))

insira a descrição da imagem aqui

como você pode ver na imagem, há uma lista dentro da lista.

Em seguida, criamos uma cópia superficial usando y = copy.copy(x) . O que o Python faz aqui é criar um novo object composto, mas os objects dentro deles estão apontando para os objects originais.

insira a descrição da imagem aqui

Na imagem, criou uma nova cópia para a lista externa. mas a lista interna permanece igual à original.

Agora nós criamos uma cópia dele usando z = copy.deepcopy(x) . O que o Python faz aqui é criar um novo object para lista externa e lista interna. como mostrado na imagem abaixo (destacado em vermelho).

insira a descrição da imagem aqui

No código final, imprime False , pois yez não são os mesmos objects.

HTH.

Adicionando a todas as definições acima, uma cópia mais profunda e mais comumente usada, está no construtor de cópia (ou no oprator de atribuição de sobrecarga) da class.

Cópia superficial -> é quando você não está fornecendo o construtor de cópia. Aqui, apenas o object é copiado, mas nem todos os membros da class são copiados.

Cópia profunda -> é quando você decidiu implementar construtor de cópia ou atribuição de sobrecarga em sua class e permite copiar todos os membros da class.

 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 } 

O construtor de cópia é usado para inicializar o novo object com o object criado anteriormente da mesma class. Por padrão, o compilador escreveu uma cópia superficial. A cópia superficial funciona bem quando a alocação de memory dinâmica não está envolvida, porque quando a alocação de memory dinâmica está envolvida, ambos os objects apontarão para a mesma localização de memory em uma pilha. Portanto, para remover esse problema, escrevemos a cópia profunda para que os dois objects tenham sua própria cópia de atributos em uma memory. Para ler os detalhes com exemplos e explicações completas, você pode ver os construtores do artigo em C ++ .

Para adicionar um pouco mais de confusão entre a cópia superficial e simplesmente atribuir um novo nome de variável à lista.

“Diga que temos:

 x = [ [1,2,3], [4,5,6], ] 

Esta declaração cria 3 listas: 2 listas internas e uma lista externa. Uma referência à lista externa é então disponibilizada sob o nome x. Se nós fizermos

 y = x 

nenhum dado é copiado. Ainda temos as mesmas 3 listas na memory em algum lugar. Tudo isso fez com que a lista externa estivesse disponível sob o nome y, além de seu nome anterior x. Se nós fizermos

 y = list(x) 

ou

 y = x[:] 

Isso cria uma nova lista com o mesmo conteúdo de x. A lista x continha uma referência às 2 listas internas, portanto, a nova lista também conterá uma referência às mesmas duas listas internas. Apenas uma lista é copiada – a lista externa. Agora existem 4 listas na memory, as duas listas internas, a lista externa e a cópia da lista externa. A lista externa original está disponível sob o nome x, e a nova lista externa é disponibilizada sob o nome y.

As listas internas não foram copiadas! Você pode acessar e editar as listas internas de x ou y neste momento!

Se você tem uma lista bidimensional (ou superior), ou qualquer tipo de estrutura de dados aninhada, e você quer fazer uma cópia completa de tudo, então você quer usar a function deepcopy () no módulo de cópia. Sua solução também funciona para listas 2-D, como itera sobre os itens na lista externa e faz uma cópia de cada um deles, em seguida, cria uma nova lista externa para todas as cópias internas. ”

fonte: https://www.reddit.com/r/learnpython/comments/1afldr/why_is_copying_a_list_so_damn_difficult_in_python/