深拷贝和浅拷贝有什么区别?

753

深拷贝和浅拷贝有什么区别?

31个回答

1037

广度 vs 深度;以您的对象为根节点,将其看作引用树。

浅复制:

Before Copy Shallow Copying Shallow Done

变量A和B引用不同的内存区域,当将B赋值给A时,两个变量引用相同的内存区域。稍后对其中任何一个的内容进行修改都会立即反映在另一个的内容中,因为它们共享内容。

深复制:

Before Copy Deep Copying Deep Done

变量A和B引用不同的内存区域,当将B赋值给A时,A指向的内存区域的值被复制到B指向的内存区域。稍后对其中任何一个的内容进行修改都只会影响到该变量本身的内容,而不会影响到另一个变量,它们的内容没有共享关系。


44
如果这个图示让你感到没有上下文的意义,这是它所属的维基百科文章链接http://en.wikipedia.org/wiki/Object_copy#Shallow_copy - corbin
4
如果进行浅拷贝,如果我们在数组B中进行任何更改,那么这些更改会反映在数组A中吗?因为A和B都指向相同的内存位置。 - tek3
6
一句话概括就是按引用传递(copy by reference)和按值传递(copy by value)。不确定答案是否正确! - mannuscript
19
9年前,我只是将图片的URL贴出来,因为当时不支持嵌入图片。因此,URL引用了其来源。后来,社区将这些URL转化为嵌入式图片,但没有编辑某种引用方式。你所指出的问题,也被一个4年前的置顶评论指出了。请看:https://stackoverflow.com/posts/184780/revisions 为什么不直接自己编辑答案并加入引用呢?也许下一次有人对我10年前的写作风格提出异议时,我可能无法回应。 - dlamblin
8
对于变量A和B,当将B分配给A时,这是否意味着代码中的"A = B"?我有些困惑,因为图像显示的是"B = A"。 - Peter Guan
显示剩余7条评论

899

浅复制尽可能少地复制。集合的浅复制是集合结构的一个副本,而不是元素。通过浅复制,两个集合现在共享各自的元素。

深复制复制一切。集合的深复制是对原始集合中所有元素进行复制的两个集合。


11
请注意,还有混合副本(不仅像懒复制那样),它只复制其中的一部分(这里有一个例子)! ;) - cregox
那么 X 的浅拷贝可以更改 X 中的元素,但深拷贝不能? - punstress
3
什么是集合结构? - mfaani
1
@Honey 集合是多种数据结构,用于存储多个数据项。在Python中,我们有元组、列表、字典等。 - Murphy
6
在过去的七年中,您可能已经发现了这一点,但其他任何人如果对此有疑问:“_shallow copy 按位复制值类型_”是正确的,但有点令人困惑。如果您拥有一个“包含” Address 对象的 Customer 对象,则“按位”复制 Customer 对象意味着Address 对象的指针/引用被复制。原始和副本都指向相同的 Address 对象,而深层复制将创建一个新的 Address 对象并指向该对象。 - Raphael Schmitz
显示剩余4条评论

221

请尝试查看以下图片

在此输入图像描述

例如,Object.MemberwiseClone方法创建一个浅表副本 (链接)

而使用 ICloneable 接口可以获得深度副本,具体请参阅这里


63
一张图片胜过千言万语。 - Levi Fuller
17
哦,来这里是为了找到意思。这是唯一有帮助的答案。 - Karan Singh
4
这是最简单的方式,只展示必要的内容。 - hina10531
3
最佳插图 - Muhammad Nayab
2
这个答案解释了按引用复制和按值复制的区别。浅拷贝和深拷贝是适用于集合的概念。请参考这个答案和这个答案 - chetan
这个概念适用于远不止集合。 - nardnob

180
简而言之,这取决于什么指向什么。在浅拷贝中,对象B指向对象A在内存中的位置。在深拷贝中,对象A内存位置中的所有内容都被复制到对象B的内存位置。 维基百科文章“对象拷贝”有一个很好的图表。

72

特别针对iOS开发者:

如果BA浅复制,那么对于原始数据,它就像B = [A assign];,对于对象,它就像B = [A retain]

B和A指向同一内存位置。

如果BA深复制,那么它就像B = [A copy];

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

B的内存地址与A相同。

B具有与A相同的内容。


9
"B的内存地址与A相同" - 怎么会这样? - user3693546
3
在深拷贝中,“B的内存地址与A的不同”。 - ismail baig

69

浅拷贝:将一个对象的成员变量值复制到另一个对象中。

深拷贝:将一个对象的成员变量值复制到另一个对象中。
               任何指针对象都会被复制并进行深度拷贝。

示例:

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

60

51

我在这里没有看到简短易懂的答案,所以我来试试。

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

深复制会复制源对象指向的任何对象,并且将该副本指向目标对象(因此每个引用对象现在都有两个)。 这个过程会递归地下降到对象树中。


37

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

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

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

只有在你理解所涉及的风险时,才可以选择进行浅复制。仅当在C++或C中处理大量指针时,对对象进行浅复制真的是一个非常糟糕的主意。

深拷贝的例子 一个例子是,在进行图像处理和物体识别时,您需要将“无关和重复的动作”屏蔽在处理区域之外。如果您使用图像指针,那么您可能有保存这些掩码图像的规范。现在...如果您对图像进行浅拷贝,当指针引用从堆栈中删除时,您将丢失引用及其副本,即在某个时刻将出现运行时错误的访问冲突。在这种情况下,您需要通过克隆来进行深拷贝以获取图像。这样,如果将来需要,您可以检索掩码。

浅拷贝的例子 我真的认为如果您知道您的程序将无限期运行,即在堆栈上进行连续的“推-弹”操作和函数调用,那么进行浅拷贝不是一个好主意。如果您正在向一个业余或初学者展示某些东西(例如C/C++教程内容),那么可能还可以。但是,如果您正在运行诸如监视和检测系统或声纳跟踪系统之类的应用程序,您不应该在对象之间进行浅拷贝,因为这将迟早导致程序崩溃。


37

什么是浅拷贝?

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

在此图中,MainObject1具有类型为int的field1和类型为ContainObjectContainObject1字段。当您对MainObject1进行浅拷贝时,将使用field1的复制值创建MainObject2,并仍指向ContainObject1本身。请注意,由于field1是基本类型,因此其值复制到field2,但由于ContainedObject1是对象,因此MainObject2仍然指向ContainObject1。因此,在MainObject1中对ContainObject1所做的任何更改都将反映在MainObject2中。

现在如果这是浅拷贝,那么深度拷贝又是什么呢?

什么是深拷贝?

深度拷贝是指复制所有字段,并复制字段所指向的动态分配内存的副本。当一个对象被复制以及它所引用的对象时,就会发生深拷贝。

在这个示例中,MainObject1具有类型为int的field1和类型为ContainObject的ContainObject1字段。当您对MainObject1进行深层复制时,将创建MainObject2,其中field2包含field1的复制值,ContainObject2包含ContainObject1的复制值。请注意,对MainObject1中的ContainObject1所做的任何更改都不会反映在MainObject2中。好文章

虽然这个例子涉及到一个名为field3的字段,但是这并不是你的错。当试图理解这样深奥的问题时,我们需要知道在ContainObject2中,这个#3是什么意思? - Robb_2015

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接