В чем разница между глубокой и мелкой копией?

в чем разница между глубокой и мелкой копией?

30 ответов


мелкие копии дублируют как можно меньше. Мелкая копия коллекции-это копия структуры коллекции, а не элементов. С неглубокой копией две коллекции теперь разделяют отдельные элементы.

глубокие копии дублируют все. Глубокая копия коллекции - это две коллекции, в которых дублируются все элементы исходной коллекции.


ширина vs глубина; подумайте в терминах дерева ссылок с вашим объектом в качестве корневого узла.

мелкий:

Before CopyShallow CopyingShallow Done

переменные A и B относятся к разным областям памяти, когда B назначается A, две переменные относятся к одной и той же области памяти. Более поздние изменения в содержимом любого из них мгновенно отражаются в содержании другого, поскольку они разделяют содержание.

глубокий:

Before CopyDeep CopyingDeep Done

переменные A и B относятся к различным областям памяти, когда B присваивается a значениям в области памяти, на которые указывает A, копируются в область памяти, на которую указывает B. Более поздние изменения в содержимом либо остаются уникальными для A или B; содержимое не является общим.


короче, это зависит от того, что указывает на то, что. В мелкой копии объект B указывает на местоположение объекта A в памяти. В deep copy все вещи в местоположении памяти объекта A копируются в местоположение памяти объекта B.

эта статья wiki имеет отличную диаграмму.

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


специально для разработчиков iOS:

если B Это мелкая копия of A, то для примитивных данных это как B = [A assign]; и как B = [A retain];

B и точка в том же месте памяти

если B Это глубокая копия of A, тогда как B = [A copy];

B и A указывают на различные памяти локации

B адрес памяти совпадает с

B имеет то же содержимое, что и A


мелкая копия: копирует значения элементов из одного объекта в другой.

Deep Copy: копирует значения элементов из одного объекта в другой.
                     Все объекты pointer дублируются и копируются глубоко.

пример:

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

попробуйте рассмотреть следующее изображение

enter image description here


Я не видел здесь короткого, простого для понимания ответа-поэтому я попробую.

с неглубокой копией любой объект, на который указывает источник, также указывает место назначения (так что никакие ссылочные объекты не копируются).

с глубокой копией копируется любой объект, на который указывает источник, и копия указывается пунктом назначения (поэтому теперь будет 2 каждого ссылочного объекта). Это повторяется вниз по дереву объектов.


{представьте себе два объекта: A и B одного типа _t(относительно C++), и вы думаете о неглубоком/глубоком копировании A В B}

Мелкая Копия: Просто делает копию ссылки на A в B. подумайте об этом как о копии адреса A. Таким образом, адреса A и B будут одинаковыми, т. е. они будут указывать на одно и то же место памяти, т. е. содержимое данных.

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

вы можете сделать мелкую копию ONLY_IF вы понимаете ставки. Когда у вас есть огромное количество указателей в C++ или C, делает мелкую копию объекта действительно плохая идея.

EXAMPLE_OF_DEEP COPY_ пример: когда вы пытаетесь выполнить обработку изображений и распознавание объектов, вам нужно замаскировать "нерелевантное и повторяющееся движение" из вашей обработки области. Если вы используете указатели на изображения, у вас может быть спецификация для сохранения этих изображений маски. СЕЙЧАС... если вы делаете неглубокую копию изображения, когда ссылки указателя убиты из стека, вы потеряли ссылку и ее копию, т. е. в какой-то момент будет ошибка времени выполнения нарушения доступа. В этом случае вам нужна глубокая копия вашего изображения путем его клонирования. Таким образом, вы можете получить маски, если они вам понадобятся в будущее.

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


просто ради легкого понимания вы можете следовать этой статье: https://www.cs.utexas.edu / ~scottm/cs307/handouts/deepCopying.htm


Мелкая Копия:

Shallow Copy


Глубокое Копирование:

Deep Copy


char * Source = "Hello, world.";

char * ShallowCopy = Source;    

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

'ShallowCopy' указывает на то же место в памяти, что и 'Source'. "DeepCopy" указывает на другое место в памяти, но содержимое то же самое.


что такое мелкая копия?

мелкая копия-это немного мудрая копия объекта. Создается новый объект, имеющий точную копию значений в исходном объекте. Если какие-либо поля объекта являются ссылками на другие объекты, копируются только ссылочные адреса, т. е. копируется только адрес памяти. Shallow Copy

в этой цифре MainObject1 поля field1 типа int и ContainObject1 типа ContainObject. Когда вы делаете мелкую копию из MainObject1, MainObject2 создано field2 содержащий скопированное значение field1 и все еще указывая на . Обратите внимание, что с field1 имеет примитивный тип, его значение копируется в field2 но поскольку ContainedObject1 - это объект, MainObject2 указан ContainObject1. Поэтому любые изменения, внесенные в ContainObject1 на MainObject1 будет отражено в MainObject2.

теперь, если это мелкая копия, давайте посмотрим, что такое глубокая копия?

о том, что глубоко Копия?

глубокая копия копирует все поля и делает копии динамически выделенной памяти, на которую указывают поля. Глубокая копия возникает, когда объект копируется вместе с объектами, на которые он ссылается. Deep Copy

на этом рисунке MainObject1 имеет поля field1 типа int и ContainObject1 типа ContainObject. Когда вы делаете глубокую копию MainObject1, MainObject2 создано field2 содержащий скопированное значение field1 и ContainObject2 содержащий скопировано значение ContainObject1. Обратите внимание на любые изменения, внесенные в ContainObject1 на MainObject1 не будет отражать в MainObject2.

хорошая статья


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

в мелкой копии создается новый экземпляр типа и значения копируются в новый экземпляр. Ссылочные указатели также копируются так же, как и значения. Поэтому ссылки указывают на исходные объекты. Любые изменения в элементах, которые хранятся по ссылке, отображаются в обоих оригинал и копия, поскольку копия ссылочного объекта не была сделана.

в глубокой копии поля, сохраненные по значению, копируются, как и раньше, но указатели на объекты, сохраненные по ссылке, не копируются. Вместо этого создается глубокая копия ссылочного объекта и сохраняется указатель на новый объект. Любые изменения, внесенные в эти объекты не влияют на другие экземпляры объектов.


'ShallowCopy' указывает на то же место в памяти, что и 'Source'. "DeepCopy" указывает на другое место в памяти, но содержимое то же самое.


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

Мелкая Копия- ссылочная переменная внутри оригинальных и мелко скопированных объектов имеет ссылку на общие


Я хотел бы привести пример, а не формальное определение.

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 !!

Неглубокое Клонирование:
Определение: "мелкая копия объекта копирует "основной" объект, но не копирует внутренние объекты." Когда пользовательский объект (например. Employee) имеет только примитивные переменные строкового типа, тогда вы используете неглубокое клонирование.

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

затем вам нужно написать код для клонирования объекта "Address", а также в переопределенном методе clone (). В противном случае объект Address не будет клонироваться и вызывает ошибку при изменении значения Address в клонированном объекте Employee, который также отражает исходный.


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

проще говоря, мелкая копия похожа на вызов по ссылке, а глубокая копия похожа на вызов по значению

в вызове по ссылке как формальные, так и фактические параметры функции относятся к одному и тому же местоположению памяти и значению.

в вызове по значению как формальные, так и фактические параметры функций относятся к разным местоположениям памяти, но имеют одинаковое значение.


представьте, что есть два массива, называемых arr1 и arr2.

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

Глубокая Копия

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

Мелкая Копия

мелкая копия-это немного мудрая копия объекта. Создается новый объект, имеющий точную копию значений в исходном объекте. Если какие-либо из полей объекта являются ссылками на другие объекты, только ссылочные адреса копируются, т. е. копируется только адрес памяти.

глубокая копия и мелкая копия пример


мелкий копирование-создание нового объекта и копирование нестатических полей текущего объекта в новый объект. Если поле является типом значения --> выполняется битовая копия поля; для ссылка типа --> ссылка копируется, но указанный объект не копируется; поэтому исходный объект и его клон ссылаются на один и тот же объект.

глубокий copy создает новый объект, а затем копирует нестатические поля текущий объект для нового объекта. Если поле тип значения --> а бит-в-бит копию поля выполняется. Если поле ссылка типа --> выполняется новая копия указанного объекта. Клонируемые классы должны быть помечены как [Serializable].


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

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

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

пояснение:

используя конструктор копирования, мы просто копируем значения данных по элементам. Этот метод копирования называется мелкой копией. Если объект является простым классом, состоящим из встроенных типов и указателей, это было бы приемлемо. Эта функция будет использовать значения и объекты, и ее поведение не будет изменено с помощью мелкой копии, копируются только адреса указателей, которые являются членами, а не значение, на которое указывает адрес. Затем значения данных объекта будут непреднамеренно изменены функцией. Когда функция выходит за рамки, копия объект со всеми его данными выводится из стека.

Если объект имеет какие-либо указатели, необходимо выполнить глубокую копию. При глубокой копии объекта для объекта в свободном хранилище выделяется память и копируются указанные элементы. Глубокая копия используется для объектов, возвращаемых функцией.


чтобы добавить больше к другим ответам,

  • мелкая копия объекта выполняет копирование по значению для типов значений свойства и скопируйте ссылки для ссылочных типов объектов.
  • глубокая копия объекта выполняет копирование по значению для типов значений на основе свойства, а также копировать по значению для ссылочных типов свойства глубоко в иерархии (ссылочных типов)

мелкая копия не создаст новую ссылку, но глубокая копия создаст новую ссылку.

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

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 + "]";
    }
}

копирование ararys :

Array-это класс, что означает, что это ссылочный тип, поэтому 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]);
    }

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

если массив содержит объекты типа значения, копируются значения;

если массив содержит ссылочный тип, копируются только ссылки-так что в результате есть два массива, члены которых ссылаются на одни и те же объекты.

чтобы создать глубокую копию, где тип ссылки дублируется, необходимо выполнить цикл через массив и клонировать каждый элемент вручную.


мелкая копия создает новый составной объект и вставляет в него ссылки на исходный объект.

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

возьмем пример.

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

над кодом печатает FALSE.

давайте посмотрим, как.

исходный составной объект x=[1,[2]] (вызывается как составной, потому что он имеет объект внутри объекта (Начало))

enter image description here

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

затем мы создаем его мелкую копию, используя y = copy.copy(x). То, что делает python здесь, это создаст новый составной объект, но объекты внутри них указывают на объекты orignal.

enter image description here

в изображении он создал новую копию для внешнего списка. но внутренний список остается прежним один.

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

enter image description here

в конце кода печатает False, поскольку y и z не являются одинаковыми объектами.

HTH.


добавление ко всем вышеперечисленным определениям еще одной и наиболее часто используемой глубокой копии находится в конструкторе копирования (или перегрузке присваивания oprator) класса.

Shallow copy -- > - это когда вы не предоставляете конструктор копирования. Здесь копируется только объект, но не все члены класса копируются.

Deep copy -- > - это когда вы решили реализовать конструктор копирования или назначение перегрузки в своем классе и позволяет копировать все члены класс.

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
}

конструктор копирования используется для инициализации нового объекта с ранее созданным объектом того же класса. По умолчанию компилятор написал неглубокую копию. Мелкая копия отлично работает, когда динамическое выделение памяти не задействовано, потому что, когда динамическое выделение памяти задействовано, оба объекта будут указывать на одно и то же место памяти в куче, поэтому для устранения этой проблемы мы написали глубокую копию, чтобы оба объекта имели свою собственную копию атрибутов в памяти. Для того чтобы прочитать подробности с полными примерами и пояснениями вы можете увидеть в статье конструкторы C++.


чтобы добавить немного больше для путаницы между мелкой копией и просто назначить новое имя переменной в список.

"скажем так:

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

этот оператор создает 3 списка: 2 внутренних списка и один внешний список. Ссылка на внешний список затем становится доступной под именем x. Если мы это сделаем

y = x

данные не копируются. У нас все еще есть те же 3 списка в памяти где-то. Все это сделало внешний список доступным под именем y, кроме того к его предыдущему имени x. Если мы это сделаем

y = list(x)

или

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/