Language agnostic 深拷贝和浅拷贝的区别是什么?

Language agnostic 深拷贝和浅拷贝的区别是什么?,language-agnostic,copy,deep-copy,shallow-copy,Language Agnostic,Copy,Deep Copy,Shallow Copy,深度拷贝和浅拷贝之间有什么区别?简言之,它取决于指向什么。在浅拷贝中,对象B指向对象a在内存中的位置。在深度复制中,对象A内存位置中的所有内容都被复制到对象B的内存位置 这篇维基文章有一个很好的图表 浅复制:将成员值从一个对象复制到另一个对象 深度复制:将成员值从一个对象复制到另一个对象。 任何指针对象都将被复制和深度复制 例如: class String { int size; char* data; }; String s1("Ace"); // s1.siz

深度拷贝和浅拷贝之间有什么区别?

简言之,它取决于指向什么。在浅拷贝中,对象B指向对象a在内存中的位置。在深度复制中,对象A内存位置中的所有内容都被复制到对象B的内存位置

这篇维基文章有一个很好的图表


浅复制:将成员值从一个对象复制到另一个对象

深度复制:将成员值从一个对象复制到另一个对象。
任何指针对象都将被复制和深度复制

例如:

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

浅拷贝尽可能少地复制。集合的浅层副本是集合结构的副本,而不是元素的副本。使用浅层副本,两个集合现在共享单个元素

深度复制复制一切。集合的深度副本是两个集合,其中原始集合中的所有元素都是重复的

char * Source = "Hello, world.";

char * ShallowCopy = Source;    

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

“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
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);
}
使用浅复制时,源指向的任何对象也会被目标指向(因此不会复制引用对象)


对于深度复制,复制源指向的任何对象,复制目标指向的对象(因此现在每个引用对象将有2个)。这将沿着对象树递归。

宽度与深度;以对象为根节点的引用树为例

浅层:

变量A和B表示不同的内存区域,当B分配给A时,两个变量表示相同的内存区域。以后对其中一个的内容所做的修改会立即反映在另一个的内容中,因为它们共享内容

深度:


变量A和B指的是不同的内存区域,当B被分配给A时,A指向的内存区域中的值被复制到B指向的内存区域中。随后对内容的修改仍然是A或B所独有的;内容不共享。

在面向对象编程中,类型包括成员字段的集合。这些字段可以通过值或引用(即,指向值的指针)存储

在浅复制中,将创建该类型的新实例,并将值复制到新实例中。引用指针也会像值一样被复制。因此,参照指向原始对象。对通过引用存储的成员所做的任何更改都将同时显示在原始和副本中,因为未对引用对象进行任何复制


在深度复制中,按值存储的字段会像以前一样被复制,但指向按引用存储的对象的指针不会被复制。取而代之的是,对被引用对象进行深度复制,并存储指向新对象的指针。对这些引用对象所做的任何更改都不会影响该对象的其他副本。

'ShallowCopy'指向内存中与'Source'相同的位置“深度复制”指向内存中的不同位置,但内容相同。

简单来说,浅层复制类似于按引用调用,而深度复制类似于按值调用

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
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);
}
在引用调用中,函数的形式参数和实际参数都引用相同的内存位置和值

在按值调用中,函数的形式参数和实际参数都指向不同的内存位置,但具有相同的值。

复制arararys:

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]);
    }
浅层克隆表示仅复制克隆数组表示的内存

如果数组包含值类型对象,则复制值

如果数组包含引用类型,则只复制引用-因此有两个数组的成员引用相同的对象


要创建引用类型重复的深度副本,必须在数组中循环并手动克隆每个元素

特别是对于iOS开发者:

如果
B
a
浅拷贝,那么对于原始数据,它就像
B=[a赋值]B=[A retain]

B和A指向同一内存位置

如果
B
a
深度副本,那么它就像
B=[a副本]

B和A指向不同的内存位置


B内存地址与A的相同


B与A的内容相同

{想象两个对象:A和B的类型相同_t(对于C++),您正在考虑将A浅/深复制到B}

浅拷贝: 简单地将a的引用复制到B中。将其视为a地址的副本。 因此,A和B的地址将是相同的,即它们将指向相同的内存位置,即数据内容

深度复制: 只需复制a的所有成员,在不同位置为B分配内存,然后将复制的成员分配给B以实现深度复制。这样,如果A变得不存在,B在内存中仍然有效。正确的术语应该是克隆,你知道它们都是完全相同的,但又不同(即在内存空间中存储为两个不同的实体)。您还可以提供克隆包装器,通过包含/排除列表决定在深度复制期间选择哪些属性。创建API时,这是一种非常常见的做法

你可以选择做一个S
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());
arr1 = arr2;   //shallow copy
arr1 = arr2.clone(); //deep copy
Employee e = new Employee(2, "john cena");
Employee e2=e.clone();
Employee e = new Employee(2, "john cena", new Address(12, "West Newbury", "Massachusetts");
import copy
x =[1,[2]]
y=copy.copy(x)
z= copy.deepcopy(x)
print(y is z)
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 !!