Каква е разликата между дълбоко копие и плитко копие?

Каква е разликата между дълбоко копие и плитко копие?


person David Locke    schedule 08.10.2008    source източник


Отговори (30)


Плитките копия се дублират възможно най-малко. Плиткото копие на колекция е копие на структурата на колекцията, а не на елементите. С плитко копие две колекции вече споделят отделните елементи.

Дълбоките копия дублират всичко. Дълбоко копие на колекция представлява две колекции с дублирани всички елементи в оригиналната колекция.

person S.Lott    schedule 08.10.2008
comment
Може би внедряването на .NET MemberwiseClone() прави повече от плитко копиране в конвенционалния смисъл - person Lu55; 19.10.2012
comment
Имайте предвид, че има и смесени копия (не само като мързеливо копие), което дублира само част от него (ето един пример)! ;) - person cregox; 10.01.2015
comment
Така че плитко копие на X може да промени елементите в X, но дълбоко копие не може? - person punstress; 24.08.2015
comment
какво е структура на колекцията? - person Honey; 12.04.2016
comment
@Honey Collections могат да бъдат различни структури от данни, които съхраняват множество елементи от данни. В python имаме кортеж, списък, речник и т.н - person Murphy; 09.08.2016
comment
Както повечето неща, това е малко зависимо от езика. Например, дефиницията на JavaScript за плитки копия е копиране на всички примитивни стойности и създаване на препратки към обекти. - person Govind Rai; 16.01.2017
comment
@AugustinePA, това зависи от естеството на колекцията. Ако направите плитко копие на int[] в Java например, елементите наистина ще бъдат копирани. - person aioobe; 19.03.2018
comment
@RoyiNamir Вероятно вече сте разбрали това през последните 7 години, но за всеки друг, който се чуди за това: плиткото копиране копира типа стойност малко по малко е правилно, но е малко объркващо. Ако имате обект Customer, който има обект Address, копирането на обекта Customer малко по малко означава, че указателят/препратката към обекта Address се копира. И оригиналът, и копието сочат към един и същ Address обект, докато дълбокото копие ще създаде нов Address обект и ще сочи към него вместо това. - person Raphael Schmitz; 21.02.2019
comment
Вижте също този отговор и този отговор за примери. - person chetan; 11.06.2020

Широчина срещу Дълбочина; мислете от гледна точка на дърво от препратки с вашия обект като основен възел.

Плитко:

Преди копиранеПлитко копиране Плитко готово

Променливите A и B се отнасят за различни области на паметта, когато B е присвоена на A, двете променливи се отнасят за една и съща област на паметта. По-късните модификации на съдържанието на един от тях незабавно се отразяват в съдържанието на други, тъй като те споделят съдържание.

Дълбок:

Преди копиранеДълбоко копиране Дълбоко готово

Променливите A и B се отнасят до различни области на паметта, когато B е присвоена на A, стойностите в областта на паметта, към която A сочи, се копират в областта на паметта, към която B сочи. По-късните модификации на съдържанието на или остават уникални за A или B; съдържанието не се споделя.

person dlamblin    schedule 08.10.2008
comment
Ето статията в Уикипедия, от която идва тази илюстрация, в случай че няма смисъл извън контекста за вас en.wikipedia.org/wiki/Object_copy#Shallow_copy - person corbin; 07.11.2013
comment
В случай на плитко копие, ако направим някакви промени в масив B, това ще бъде ли отразено в масив A, тъй като A и B сочат към едно и също място в паметта? - person tek3; 16.01.2015
comment
Така че плиткото копие означава, че само препратка към оригиналния обект е достъпна за така нареченото копие. Всяка промяна в оригиналния обект ще бъде репликирана към новия? Дълбокото копие би клонирало оригиналния обект и би направило ново несвързано копие. - person Swanidhi; 25.03.2016
comment
В един ред неговото копие по препратка срещу копие по стойност. Не съм сигурен дали отговорът е правилен! - person mannuscript; 05.06.2017
comment
изображения, директно взети от wikipedia без цитиране - person jasonleonhard; 05.09.2017
comment
@jasonleonhard И така, преди 9 години просто сложих URL адреси към изображенията, защото вграждането на изображения не се поддържаше. Така URL адресът цитира своя източник. По-късно общността превърна URL адресите във вградени изображения, без да редактира някакъв вид цитат върху тях. 4-годишният топ коментар също посочва това, което изтъквате. Разгледайте: stackoverflow.com/posts/184780/revisions Защо просто не редактирате сами цитат в отговора? Може да бъда недостъпен следващия път, когато някой се оплаква от 10-годишния ми стил на писане. - person dlamblin; 07.09.2017
comment
Разбира се, ще добавя цитата, който сте прекъснали. Независимо кой е човекът, ще продължа да съобщавам, ако видя някой да използва чужда работа без цитат, защото това е правилното нещо. Въпреки че в чест на отговора ви, бихте могли да добавите цитат също толкова бързо, колкото да напишете отговор. Добра форма е да цитирате източници, които по принцип не са ваши. Най-добри пожелания. - person jasonleonhard; 07.09.2017
comment
За променливи A и B, когато B е присвоено на A, това не означава ли A = B в кода? Някак си объркан, тъй като изображението отразява B = A. - person Peter Guan; 19.09.2018
comment
Както предлага @Mannu, този отговор обяснява копиране по препратка срещу копие по стойност. Концепцията за плитко срещу дълбоко копиране е приложима за колекции, които имат препратки като елементи. Ако елементите както на стария, така и на новия масив са препратки към едни и същи обекти, тогава това е плитко копие. Ако препратките се дереферират, за да се създадат нови обекти, това е дълбоко копие. По принцип, ако нови обекти се създават рекурсивно, това е дълбоко копие. Това е обяснено в приетия отговор. Този отговор го обяснява добре с помощта на примери. - person chetan; 11.06.2020
comment
@chetanraina напълно съгласен, просто един обект е колекция от 0 ред. Това, което правите с даден обект (референтно копиране или копиране на стойност), е приложимо за всяка част от колекцията, когато прилагате съответно плитко или дълбоко копиране. Опитах се да го запазя супер кратко като резюме на лесната за намиране статия в wikipedia или може би страницата на нечий учебник. - person dlamblin; 16.06.2020
comment
@dlamblin няма проблем, стига да говорим за единични обекти, които не са колекции. Но става погрешно в контекста на колекциите. Ако разгледаме копирането на колекции, тогава това, което сте показали като дълбоко копие, всъщност е плитко копие (и двете колекции имат едни и същи препратки X1, X2, X3) и това, което сте показали като плитко копие, всъщност не е копиране, защото не е създадено копие, на В е присвоена само нова справка. - person chetan; 17.06.2020
comment
@PeterGuan Зависи как го гледаш. С настоящата формулировка и двете могат да бъдат верни. Ако имам кутия A и кутия B, изразът B е присвоен на A няма много смисъл. В отговора авторът е имал предвид B е присвоено на съдържанието на A, където съдържанието е препратката към някаква структура. (съдържанието на A е присвоено на B също би работило, но противоречи на отговора тук.) - person 3limin4t0r; 05.08.2020

Накратко, зависи какво сочи към какво. В плитко копие обект B сочи към местоположението на обект A в паметта. При дълбоко копиране всички неща в местоположението на паметта на обект A се копират в местоположението на паметта на обект B.

Тази статия в wiki има страхотна диаграма.

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

person helloandre    schedule 08.10.2008

Опитайте се да разгледате следното изображение

въведете описание на изображението тук

Например Object.MemberwiseClone създава плитко копие връзка

и с помощта на интерфейса ICloneable можете да получите задълбочено копие, както е описано тук

person Alexandr    schedule 15.06.2016
comment
Една снимка струва повече от хиляда думи. - person Levi Fuller; 26.06.2016
comment
О, момче, дойдох тук, за да разбера значението. Това е единственият отговор, който помогна. - person Karan Singh; 16.06.2017
comment
Това е най-простият и въпреки това показва само това, което е необходимо. - person hina10531; 19.03.2018
comment
най-добрата илюстрация - person Muhammad Nayab; 22.01.2019
comment
Този отговор обяснява копиране по препратка спрямо копие по стойност. Плитко копие срещу дълбоко копие е концепция, която се прилага за колекциите. Вижте този отговор и този отговор. - person chetan; 11.06.2020
comment
Концепцията се прилага за много повече от колекции - person nardnob; 06.12.2020

Специално за разработчици на iOS:

Ако B е плитко копие на A, тогава за примитивни данни е като B = [A assign];, а за обекти е като B = [A retain];

B и A сочат към едно и също място в паметта

Ако B е задълбочено копие на A, то е като B = [A copy];

B и A сочат към различни места в паметта

Адресът на паметта B е същият като този на A

Б има същото съдържание като това на А

person Abhishek Bedi    schedule 23.01.2013
comment
Адресът на паметта B е същият като този на A - Как така? - person ; 26.10.2015
comment
В Deep Copy адресът на памет B НЕ е същият като този на A - person ismail baig; 08.05.2018

Плитко копие: Копира стойностите на членовете от един обект в друг.

Дълбоко копиране: Копира стойностите на членовете от един обект в друг.
Всички указателни обекти се дублират и дълбоко копират.

Пример:

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.)
person Martin York    schedule 08.10.2008

Само за по-лесно разбиране можете да следвате тази статия: https://www.cs.utexas.edu/~scottm/cs307/handouts/deepCopying.htm


Плитко копие:

Плитко копие


Дълбоко копие:

Дълбоко копие

person Touchstone    schedule 19.03.2014

Не съм виждал кратък, лесен за разбиране отговор тук - така че ще опитам.

С плитко копие всеки обект, към който сочи източникът, също се сочи към дестинацията (така че да не се копират обекти, към които има препратки).

С дълбоко копие всеки обект, към който сочи източникът, се копира и към копието се сочи дестинацията (така че сега ще има 2 от всеки рефериран обект). Това рекурсира надолу по дървото на обектите.

person Bill K    schedule 08.10.2008

{Представете си два обекта: A и B от същия тип _t (по отношение на C++) и мислите за плитко/дълбоко копиране на A към B}

Плитко копие: Просто правете копие на препратката към A в B. Мислете за това като за копие на адреса на A. Така че адресите на A и B ще бъдат еднакви, т.е. те ще сочат към едно и също място в паметта, т.е. съдържанието на данните.

Дълбоко копие: Просто правете копие на всички членове на A, разпределяте памет на друго място за B и след това присвоявате копираните членове на B, за да постигнете дълбоко копие. По този начин, ако A стане несъществуващо, B все още е валидно в паметта. Правилният термин за използване би бил клониране, където знаете, че и двете са напълно еднакви, но все пак различни (т.е. съхранени като две различни единици в пространството на паметта). Можете също да предоставите вашата обвивка на клонинг, където можете да решите чрез списък за включване/изключване кои свойства да изберете по време на дълбоко копиране. Това е доста често срещана практика, когато създавате API.

Можете да изберете да направите плитко копие САМО_АКО разбирате заложените залози. Когато имате огромен брой указатели, с които трябва да се справите в C++ или C, правенето на плитко копие на обект е НАИСТИНА лоша идея.

EXAMPLE_OF_DEEP COPY_ Например, когато се опитвате да извършите обработка на изображения и разпознаване на обекти, трябва да маскирате „Неуместно и повтарящо се движение“ от вашите зони за обработка. Ако използвате указатели на изображения, тогава може да имате спецификацията да запазите тези маскирани изображения. СЕГА... ако направите плитко копие на изображението, когато препратките към указателя са УБИТИ от стека, вие сте загубили препратката и нейното копие, т.е. ще има грешка по време на изпълнение на нарушение на достъпа в даден момент. В този случай това, от което се нуждаете, е дълбоко копие на вашето изображение, като го КЛОНИРАТЕ. По този начин можете да извлечете маските, в случай че ви потрябват в бъдеще.

EXAMPLE_OF_SHALLOW_COPY Не съм много осведомен в сравнение с потребителите в StackOverflow, така че можете да изтриете тази част и да поставите добър пример, ако можете да поясните. Но наистина мисля, че не е добра идея да правите плитко копиране, ако знаете, че програмата ви ще работи безкраен период от време, т.е. непрекъсната операция "push-pop" над стека с извиквания на функции. Ако демонстрирате нещо на аматьор или начинаещ човек (напр. C/C++ уроци), тогава вероятно е добре. Но ако работите с приложение като система за наблюдение и откриване или сонарна система за проследяване, не трябва да продължавате плитко да копирате вашите обекти наоколо, защото това ще убие вашата програма рано или късно.

person ha9u63ar    schedule 31.01.2013

char * Source = "Hello, world.";

char * ShallowCopy = Source;    

char * DeepCopy = new char(strlen(Source)+1);
strcpy(DeepCopy,Source);        

„ShallowCopy“ сочи към същото място в паметта като „Source“. „DeepCopy“ сочи към различно място в паметта, но съдържанието е същото.

person John Dibling    schedule 08.10.2008
comment
Най-добър отговор. Благодаря. - person Don Dilanga; 21.12.2020

Какво е плитко копиране?

Плиткото копие е побитово копие на обект. Създава се нов обект, който има точно копие на стойностите в оригиналния обект. Ако някое от полетата на обекта е препратка към други обекти, само референтните адреси се копират, т.е. само адресът на паметта се копира. Плитко копие

На тази фигура MainObject1 има полета field1 от тип int и ContainObject1 от тип ContainObject. Когато направите плитко копие на MainObject1, MainObject2 се създава с field2, съдържащо копираната стойност на field1 и все още сочещо към самото ContainObject1. Имайте предвид, че тъй като field1 е от примитивен тип, неговата стойност се копира в field2, но тъй като ContainedObject1 е обект, MainObject2 все още сочи към ContainObject1. Така че всички промени, направени в ContainObject1 в MainObject1, ще бъдат отразени в MainObject2.

Сега, ако това е плитко копие, нека да видим какво е дълбоко копие?

Какво е дълбоко копиране?

Дълбокото копие копира всички полета и прави копия на динамично разпределената памет, посочена от полетата. Дълбоко копие възниква, когато даден обект се копира заедно с обектите, към които се отнася. Дълбоко копие

На тази фигура MainObject1 има полета field1 от тип int и ContainObject1 от тип ContainObject. Когато правите дълбоко копие на MainObject1, MainObject2 се създава с field2, съдържащо копираната стойност на field1 и ContainObject2, съдържащо копираната стойност на ContainObject1. Имайте предвид, че всички промени, направени в ContainObject1 в MainObject1, няма да се отразят в MainObject2.

добра статия

person atish shimpi    schedule 18.12.2014
comment
вината не е ваша, въпреки че този пример се отнася до field3, което, когато е в състояние да се опита да разбере нещо толкова дълбоко като този проблем, къде се случва това #3 в този пример ContainObject2 ? - person Robb_2015; 29.12.2015

В обектно-ориентираното програмиране типът включва колекция от полета-членове. Тези полета могат да се съхраняват или по стойност, или по препратка (т.е. указател към стойност).

В плитко копие се създава нов екземпляр от типа и стойностите се копират в новия екземпляр. Референтните указатели също се копират точно като стойностите. Следователно препратките сочат към оригиналните обекти. Всички промени в членовете, които се съхраняват чрез препратка, се появяват както в оригинала, така и в копието, тъй като не е направено копие на посочения обект.

В дълбоко копие полетата, които се съхраняват по стойност, се копират както преди, но указателите към обекти, съхранявани по препратка, не се копират. Вместо това се прави дълбоко копие на посочения обект и се съхранява указател към новия обект. Всички промени, които се правят в тези референтни обекти, няма да засегнат други копия на обекта.

person Jeffrey L Whitledge    schedule 08.10.2008

„ShallowCopy“ сочи към същото място в паметта като „Source“. „DeepCopy“ сочи към различно място в паметта, но съдържанието е същото.

person GovindaRaju    schedule 21.02.2011
comment
Това е малко подвеждащо. Както плиткото, така и дълбокото копие ще копират обекта на ново място в паметта, дълбокото също ще копира дъщерните обекти, докато плиткото просто ще накара новите обекти да се отнасят за старите деца. Трудно е да се чете, без да се позовава на оригиналния обект. - person Bill K; 05.04.2017

Плитко клониране:
Определение: „Плитко копие на обект копира „основния“ обект, но не копира вътрешните обекти.“ Когато персонализиран обект (напр. Служител) има само примитивни променливи от тип String, тогава използвате плитко клониране.

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

Връщате super.clone(); в отменения метод clone() и работата ви приключва.

Дълбоко клониране:
Определение: „За разлика от плиткото копие, дълбокото копие е напълно независимо копие на обект.“
Означава, че обект Employee съдържа друг потребителски обект:

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

След това трябва да напишете кода, за да клонирате и обекта „Адрес“ в заменения метод clone(). В противен случай обектът Address няма да се клонира и причинява грешка, когато промените стойността на Address в клониран обект Employee, който отразява и оригиналния.

person Arun Raaj    schedule 26.09.2017

Бих искал да дам пример, а не формалната дефиниция.

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

Този код показва плитко копие:

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

Този код показва дълбоко копие:

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 !!
person Vivek Mehta    schedule 24.01.2018
comment
получавам 1 1 4 4 4 4 4 4 - person Suresh Prajapati; 11.08.2019
comment
в дълбоко копие направете copyObject.a = 8 и след това проверете. надявам се да получите правилен отговор. - person Vivek Mehta; 12.08.2019
comment
object.assign({},arr) няма да създаде дълбокото копие, да предположим, че имаме следния обект var source = {foo:1,name:Testing,c:{age:34}} var dCopy = Object.assign({ },източник) console.log(dCopy.c.age) console.log(Source deep ${source.c.age}) source.c.age = 3 console.log(dCopy.c.age) console.log(Source deep ${source.c.age}) - person Swarup Chavan; 29.07.2020

Дълбоко копиране

Дълбокото копие копира всички полета и прави копия на динамично разпределената памет, посочена от полетата. Дълбоко копие възниква, когато даден обект се копира заедно с обектите, към които се отнася.

Плитко копие

Плиткото копие е побитово копие на обект. Създава се нов обект, който има точно копие на стойностите в оригиналния обект. Ако някое от полетата на обекта е препратка към други обекти, само референтните адреси се копират, т.е. само адресът на паметта се копира.

person Sunil Kumar Sahoo    schedule 16.09.2014
comment
Тази връзка за съжаление вече не работи - сега сочи към статия от февруари 2019 г. относно уеб дизайна (освен ако авторът не е ясновидец?). - person PhilPhil; 05.04.2019

Плитко копие- Референтната променлива в оригиналните и плитко копирани обекти има препратка към общ обект.

Дълбоко копие- Референтната променлива в оригиналните и дълбоко копирани обекти има препратка към различен обект.

клонирането винаги прави плитко копиране.

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

основният клас е следният -

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
      
} 

Резултатът от горното ще бъде-

невярно вярно вярно

невярно невярно невярно

Всяка промяна, направена в оригиналния обект, ще се отрази в плитък обект, а не в дълбок обект.

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

OutPut- ViSuaLBaSiC C

person Community    schedule 07.05.2015

С прости думи, плиткото копие е подобно на извикване по референция, а дълбокото копие е подобно на извикване по стойност

При извикване по препратка както формалните, така и действителните параметри на функция се отнасят до едно и също място в паметта и стойността.

При извикване по стойност както формалните, така и действителните параметри на функция се отнасят до различно място в паметта, но имат една и съща стойност.

person santhosh    schedule 02.12.2011

Представете си, че има два масива, наречени arr1 и arr2.

arr1 = arr2;   //shallow copy
arr1 = arr2.clone(); //deep copy
person PeerNet    schedule 29.05.2015

Плиткото копие конструира нов съставен обект и вмъква в него своите препратки към оригиналния обект.

За разлика от плиткото копиране, дълбокото копиране конструира нов съставен обект и също така вмъква копия на оригиналните обекти на оригиналния съставен обект.

Да вземем пример.

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

Горният код отпечатва FALSE.

Да видим как.

Оригинален съставен обект x=[1,[2]] (наречен като съставен, защото има обект вътре в обекта (начало))

въведете описание на изображението тук

както можете да видите на изображението, има списък в списъка.

След това създаваме негово плитко копие с помощта на y = copy.copy(x). Това, което Python прави тук, е, че ще създаде нов съставен обект, но обектите вътре в тях сочат към оригиналните обекти.

въведете описание на изображението тук

В изображението е създадено ново копие за външен списък. но вътрешният списък остава същият като оригиналния.

Сега създаваме дълбоко копие на него с помощта на z = copy.deepcopy(x). това, което python прави тук, е, че ще създаде нов обект за външен списък, както и за вътрешен списък. както е показано на изображението по-долу (маркирано в червено).

въведете описание на изображението тук

В края кодът отпечатва False, тъй като y и z не са едни и същи обекти.

HTH.

person Sushant    schedule 20.01.2018

За да добавите още към други отговори,

  • плитко копие на обект изпълнява копиране по стойност за свойства, базирани на типове стойности, и копиране по препратка за свойства, базирани на референтни типове.
  • Дълбоко копие на обект извършва копиране по стойност за свойства, базирани на типове стойности, както и копиране по стойност за свойства, базирани на референтни типове, дълбоко в йерархията (на референтни типове)
person VSS    schedule 29.09.2016

Плиткото копиране е създаване на нов обект и след това копиране на нестатичните полета на текущия обект в новия обект. Ако дадено поле е тип стойност --> се изпълнява битово копие на полето; за референтен тип --> препратката се копира, но препратеният обект не е; следователно оригиналният обект и неговият клонинг се отнасят за един и същ обект.

Дълбокото копиране създава нов обект и след това копира нестатичните полета на текущия обект в новия обект. Ако дадено поле е тип стойност --> се изпълнява битово копие на полето. Ако дадено поле е референтен тип --> се изпълнява ново копие на препоръчания обект. Класовете, които ще бъдат клонирани, трябва да бъдат маркирани като [Serializable].

person Rajaram Shelar    schedule 08.08.2013

Взето от [блог]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Дълбоко копиране включва използването на съдържанието на един обект за създаване на друг екземпляр от същия клас. В дълбоко копие двата обекта може да съдържат една и съща информация, но целевият обект ще има свои собствени буфери и ресурси. унищожаването на който и да е обект няма да засегне останалия обект. Претовареният оператор за присвояване ще създаде дълбоко копие на обекти.

Плиткото копиране включва копиране на съдържанието на един обект в друг екземпляр от същия клас, като по този начин се създава огледален образ. Благодарение на директното копиране на препратки и указатели, двата обекта ще споделят едно и също външно съдържание на другия обект, за да бъдат непредвидими.

Обяснение:

С помощта на конструктор за копиране ние просто копираме стойностите на данните член по член. Този метод на копиране се нарича плитко копиране. Ако обектът е прост клас, състоящ се от вградени типове и без указатели, това би било приемливо. Тази функция ще използва стойностите и обектите и нейното поведение няма да бъде променено с плитко копие, копират се само адресите на указателите, които са членове, а не стойността, към която сочи адресът. След това стойностите на данните на обекта биха били неволно променени от функцията. Когато функцията излезе извън обхвата, копието на обекта с всичките му данни се изважда от стека.

Ако обектът има указатели, трябва да се изпълни дълбоко копие. С дълбокото копие на обект се разпределя памет за обекта в свободното хранилище и посочените елементи се копират. Задълбочено копие се използва за обекти, които се връщат от функция.

person Santosh    schedule 07.03.2014

Разбрах от следващите редове.

Плиткото копиране копира тип стойност(int, float, bool) полета в целевия обект и референтните типове на обекта (низ, клас и т.н.) се копират като препратки в целевия обект . В тази целева препратка типовете ще сочат към местоположението на паметта на изходния обект.

Дълбокото копиране копира стойността на обекта и референтните типове в пълно ново копие на целевите обекти. Това означава, че както стойностните типове, така и референтните типове ще бъдат разпределени на нови места в паметта.

person Nayas Subramanian    schedule 28.07.2018

Плиткото копие няма да създаде нова препратка, но дълбокото копие ще създаде новата препратка.

Ето програмата за обяснение на дълбокото и плитко копие.

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 + "]";
    }
}
person Lova Chittumuri    schedule 06.03.2017

Копиране на ararys:

Масивът е клас, което означава, че е референтен тип, така че array1 = array2 води до две променливи, които препращат към един и същи масив.

Но вижте този пример:

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

плитко клониране означава, че се копира само паметта, представена от клонирания масив.

Ако масивът съдържа обекти от тип стойност, стойностите се копират;

ако масивът съдържа референтен тип, само препратките се копират - така че в резултат има два масива, чиито членове препращат към едни и същи обекти.

За да създадете задълбочено копие - където референтният тип се дублира, трябва да преминете през масива и да клонирате всеки елемент ръчно.

person komizo    schedule 19.12.2012
comment
Не знам за други езици, но в C#/VB плиткото копиране на масив от типове стойност не копира стойностите. Двата масива се отнасят за едни и същи обекти. Добавете бутон към формуляр и добавете този код, за да видите: 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]); } - person DeanOC; 20.12.2012
comment
прав си, коригирах отговора си, за да бъда по-точен, използвайки клонинг върху масиви. Напълно сте прав, че плиткото копиране на масив от типове стойности не копира стойностите, но използването на клониране върху масив го прави. Опитах се да обясня това, опитайте. Благодаря - person komizo; 20.12.2012

Като добавим към всички по-горе дефиниции, още едно и най-често използвано дълбоко копие е в конструктора за копиране (или оператора за претоварване на присвояването) на класа.

Плитко копиране --> е, когато не предоставяте конструктор за копиране. Тук само обектът се копира, но не всички членове на класа се копират.

Дълбоко копиране --> е, когато сте решили да внедрите конструктор за копиране или присвояване на претоварване във вашия клас и позволява копиране на всички членове на класа.

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
}
person Avinash Goud N J    schedule 20.12.2013

Конструкторът за копиране се използва за инициализиране на новия обект с предварително създадения обект от същия клас. По подразбиране компилаторът написа плитко копие. Плиткото копиране работи добре, когато не е включено динамично разпределение на паметта, защото когато е включено динамично разпределение на памет, тогава и двата обекта ще сочат към едно и също място в паметта в купчина. Следователно, за да премахнем този проблем, ние написахме дълбоко копие, така че и двата обекта да имат собствено копие на атрибути в спомен. За да прочетете подробностите с пълни примери и обяснения, можете да видите статията C++ конструктори .

person royal52    schedule 08.02.2014

За да добавите още малко за объркване между плитко копиране и просто присвояване на ново име на променлива към списъка.

„Кажете, че имаме:

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

Този оператор създава 3 списъка: 2 вътрешни списъка и един външен списък. След това се предоставя препратка към външния списък под името x. Ако го направим

y = x

никакви данни не се копират. Все още имаме същите 3 списъка в паметта някъде. Всичко, което направи, е да направи външния списък достъпен под името y, в допълнение към предишното му име x. Ако го направим

y = list(x)

or

y = x[:]

Това създава нов списък със същото съдържание като x. Списък x съдържа препратка към 2 вътрешни списъка, така че новият списък също ще съдържа препратка към същите тези 2 вътрешни списъка. Копира се само един списък – външният списък. Сега има 4 списъка в паметта, двата вътрешни списъка, външния списък и копието на външния списък. Оригиналният външен списък е достъпен под името x, а новият външен списък е достъпен под името y.

Вътрешните списъци не са копирани! Можете да получите достъп и да редактирате вътрешните списъци от x или y в този момент!

Ако имате двуизмерен (или по-висок) списък или някакъв вид вложена структура от данни и искате да направите пълно копие на всичко, тогава искате да използвате функцията deepcopy() в модула за копиране. Вашето решение работи и за 2-D списъци, тъй като итерира елементите във външния списък и прави копие на всеки от тях, след което изгражда нов външен списък за всички вътрешни копия."

източник: https://www.reddit.com/r/learnpython/comments/1afldr/why_is_copying_a_list_so_damn_difficult_in_python/

person Lance Ruo Zhang    schedule 12.01.2017

person    schedule
comment
Това не е добър пример. Плитките копия се използват най-вече за бързо копиране на обекти, без копиране на данните, но след като обектът трябва да модифицира споделените данни, се прави дълбоко копие от него. Вашият пример вероятно ще обърка начинаещите. - person CMircea; 17.04.2010
comment
това работи само на езици, които използват указатели за представяне на низове. Въпросът, който DHA се опитва да направи, е, че плиткото копиране само дублира указатели към идентичното (единствено) оригинално съдържание, докато дълбокото копие също клонира референтното съдържание на указателите. И двата метода копират повърхностно съдържание. Ако езикът съхранява низове като съдържание на повърхностен литерал, напр. вътре в WAV хедър, този пример няма да работи. Имайте предвид, че това вероятно е твърде придирчиво за повечето проблеми от реалния живот, които не са езотерични. - person DragonLord; 16.11.2014