代码之家  ›  专栏  ›  技术社区  ›  David Locke

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

  •  754
  • David Locke  · 技术社区  · 16 年前

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

    31 回复  |  直到 11 年前
        1
  •  955
  •   thyu    4 年前

    Before Copy Shallow Copying Shallow Done

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

    Before Copy Deep Copying Deep Done

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

        2
  •  868
  •   S.Lott    16 年前

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

        3
  •  171
  •   Ray    16 年前

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

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

        4
  •  167
  •   Community CDub    8 年前

    enter image description here

    例如 Object.MemberwiseClone 创建一个 复制 link

    和使用 易克隆的 深的 here

        5
  •  71
  •   mfaani    9 年前

    如果 B 是一个 A ,那么对于原始数据 B = [A assign]; 对于物体,它就像 B = [A retain] ;

    如果 B 属于 A. 那就是 B = [A copy];

    B内存地址与A的相同

    B和A的内容相同

        6
  •  66
  •   Loki Astari    16 年前

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

    深度复制:将成员值从一个对象复制到另一个对象。

    例子:

    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.)
    
        7
  •  54
  •   Touchstone    9 年前
        8
  •  50
  •   Bill K    8 年前

    我还没有看到一个简短易懂的答案,所以我要试试看。

    使用浅复制时,源指向的任何对象也会被目标指向(因此不会复制引用对象)。

        9
  •  38
  •   ha9u63a7    8 年前

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

    浅拷贝:

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

    您可以选择进行浅拷贝 除非 你明白其中的利害关系。当你在C++或C中有大量的指针处理时,做一个对象的浅拷贝是 真正地 一个坏主意。

    例如,当您尝试进行图像处理和对象识别时,您需要屏蔽处理区域之外的“不相关和重复运动”。如果您使用的是图像指针,那么您可能有保存这些掩码图像的规范。现在如果执行映像的浅层复制,当指针引用从堆栈中删除时,您将丢失引用及其副本,即在某个点上会出现访问冲突的运行时错误。在这种情况下,您需要的是通过克隆图像来获得图像的深度副本。通过这种方式,您可以检索面具,以防将来需要它们。

    与StackOverflow中的用户相比,我的知识不是非常渊博,所以请随意删除此部分,如果您能够澄清,请举一个好的示例。但我真的认为,如果你知道你的程序将运行无限长的一段时间,即通过函数调用在堆栈上进行连续的“push-pop”操作,那么进行浅层复制不是一个好主意。如果你正在向一个业余爱好者或新手演示一些东西(例如C/C++教程的东西),那么它可能是可以的。但是,如果您正在运行一个应用程序,例如监视和探测系统,或者声纳跟踪系统,那么您不应该一直对周围的对象进行肤浅的复制,因为它迟早会杀死您的程序。

        10
  •  35
  •   John Dibling    16 年前
    char * Source = "Hello, world.";
    
    char * ShallowCopy = Source;    
    
    char * DeepCopy = new char(strlen(Source)+1);
    strcpy(DeepCopy,Source);        
    

    “ShallowCopy”指向内存中与“Source”相同的位置。 “DeepCopy”指向内存中的不同位置,但内容相同。

        11
  •  31
  •   smci    8 年前

    什么是浅拷贝?

    Shallow Copy

    MainObject1 有田地 field1 ContainObject1 ContainObject . 当你做一个肤浅的副本 主要目标1 , MainObject2 field2 包含复制的 字段1 容器对象1 字段1 是基元类型,其值复制到 但是自从 ContainedObject1 是一个物体, 仍然指向 容器对象1 . 那么对 在里面 主要目标1 将反映在 .

    什么是深度复制?

    Deep Copy

    字段1 容器对象1 类型 容器对象 主要目标1 , 主要对象2 字段2 包含复制的 ContainObject2 包含复制的 容器对象1 主要目标1 不会反映在 主要对象2

    good article

        12
  •  16
  •   Jeffrey L Whitledge    16 年前

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

        13
  •  13
  •   GovindaRaju    14 年前

    “ShallowCopy”指向内存中与“Source”相同的位置“DeepCopy”指向内存中的不同位置,但内容相同。

        14
  •  12
  •   Arun Raaj    7 年前


    定义:“对象的浅拷贝复制主对象,但不复制内部对象。”

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

    你回来 super.clone(); 在重写的clone()方法中,您的作业结束。

    深度克隆 :
    定义:“与浅拷贝不同,深拷贝是对象的完全独立拷贝。”
    表示员工对象持有另一个自定义对象时:

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

        15
  •  12
  •   thirtydot    7 年前

    我想举个例子,而不是正式的定义。

    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 !!
    
        16
  •  12
  •   Jean-François Fabre    6 年前

    深度复制

    浅拷贝

    浅复制是对象的逐位复制。将创建一个新对象,该对象具有原始对象中值的精确副本。如果对象的任何字段是对其他对象的引用,则只复制引用地址,即只复制内存地址。

        17
  •  10
  •   Dour High Arch    16 年前
    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
    
        18
  •  9
  •   Community CDub    4 年前

    浅拷贝 常见的 对象

    深度复制 -原始对象和深度复制对象中的引用变量引用到 对象

    克隆总是做浅拷贝。

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

    输出- 视基C

        19
  •  8
  •   PeerNet    10 年前

    arr1 = arr2;   //shallow copy
    arr1 = arr2.clone(); //deep copy
    
        20
  •  7
  •   santhosh    13 年前

    在引用调用中,函数的形式参数和实际参数都引用相同的内存位置和值。

        21
  •  7
  •   Sushant    7 年前

    与浅复制不同,deepcopy构造新的复合对象,并插入原始复合对象的原始对象的副本。

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

    上面的代码打印错误。

    让我们看看如何。

    原始复合对象 x=[1,[2]] (称为复合,因为它在object(初始)中有object)

    enter image description here

    然后我们使用 y = copy.copy(x) . python在这里所做的是,它将创建一个新的复合对象,但其中的对象指向原始对象。

    enter image description here

    在图像中,它为外部列表创建了一个新副本。但内部列表仍与原始列表相同。

    现在,我们使用 z = copy.deepcopy(x) . python在这里所做的是,它将为外部列表和内部列表创建新对象。如下图所示(红色高亮显示)。

    enter image description here

    最后打印代码 False ,因为y和z不是相同的对象。

    嗯。

        22
  •  5
  •   notytony    13 年前
    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);
    }
    
        23
  •  4
  •   S2S2    8 年前

    为了补充其他答案,

    • 对象的深度副本对基于属性的值类型执行按值复制 属性,以及基于引用类型的按值复制 层次结构中深层的属性(引用类型)
        24
  •  4
  •   Pang Ajmal PraveeN    6 年前

    浅复制不会创建新引用,但深复制将创建新引用。

    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 + "]";
        }
    }
    
        25
  •  3
  •   Santosh    11 年前

    摘自[博客]: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

    深度复制

    浅拷贝

    说明:

    使用复制构造函数,我们只需逐个成员复制数据值。这种复制方法称为浅复制。如果对象是一个简单的类,由内置类型组成,没有指针,这是可以接受的。此函数将使用值和对象,其行为不会因浅拷贝而改变,只复制作为成员的指针的地址,而不复制地址所指向的值。然后,该函数会无意中更改对象的数据值。当函数超出范围时,对象及其所有数据的副本将从堆栈中弹出。

    如果对象有任何指针,则需要执行深度复制。对于对象的深度复制,内存分配给空闲存储中的对象,并复制指向的元素。深度副本用于从函数返回的对象。

        26
  •  3
  •   Nayas Subramanian    6 年前

    我是从以下几句话中理解的。

    值类型 将目标对象中的(int、float、bool)字段和对象的引用类型(字符串、类等)复制为 参考资料 在目标对象中。在此情况下,目标引用类型将指向源对象的内存位置。

    深度复制将对象的值和引用类型复制到目标对象的完整新副本中。这意味着值类型和引用类型都将被分配一个新的内存位置。

        27
  •  2
  •   Rajaram Shelar    11 年前

    浅的 复制是创建一个新对象,然后将当前对象的非静态字段复制到新对象。如果字段是值类型-->执行字段的逐位复制;暂时 参考类型

    深的 值类型 --&燃气轮机;将执行引用对象的新副本。要克隆的类必须标记为[Serializable]。

        28
  •  1
  •   komizo    12 年前

    在引用同一数组的两个变量中。

    但看看这个例子:

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

    表示仅复制克隆数组表示的内存。

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

    .

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

        29
  •  1
  •   royal52    11 年前

    为了阅读包含完整示例和解释的详细信息,您可以阅读本文 C++ constructors

        30
  •  1
  •   Lance Ruo Zhang    8 年前

    为了避免在浅拷贝和简单地给列表分配一个新的变量名之间产生混淆,只需再添加一点。

    “假设我们有:

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

    y = x
    

    没有数据被复制。我们在内存中的某个地方仍然有相同的3个列表。所有这些都是为了使外部列表除了以前的名称x之外,还可以使用名称y。如果我们这样做

    y = list(x)
    

    y = x[:]
    

    这将创建一个与x内容相同的新列表。列表x包含对2个内部列表的引用,因此新列表也将包含对相同的2个内部列表的引用。只有一个列表复制到外部列表。

    内部列表尚未复制!此时,您可以从x或y访问和编辑内部列表!

    资料来源: https://www.reddit.com/r/learnpython/comments/1afldr/why_is_copying_a_list_so_damn_difficult_in_python/