深拷贝与浅拷贝[重复]
Posted
技术标签:
【中文标题】深拷贝与浅拷贝[重复]【英文标题】:Deep copy vs Shallow Copy [duplicate] 【发布时间】:2011-02-09 02:40:39 【问题描述】:可能重复:What is the difference between a deep copy and a shallow copy?
深拷贝和浅拷贝有什么区别。拷贝构造函数做了什么类型的拷贝?
【问题讨论】:
重复***.com/questions/184710/… 第一个问题是重复的,但我找不到第二个问题,尽管这可能是因为它没有明确说明。 @Ankur:在您的第二个问题中,您是在询问默认的复制构造函数吗? 深拷贝和浅拷贝这两个术语通常不会在 C++ 中使用,因为它们不能很好地映射到该语言。在 Java 和其他几种语言中,这种区别更有用,因为它们基于引用的语义,在大多数情况下,浅拷贝是不可避免的。在 C++ 中,对象是按值复制的,真正的浅拷贝非常罕见,但默认的复制构造函数也不会实现深拷贝。这些术语在 C++ 中没有意义 【参考方案1】:浅拷贝:
副本的某些成员可能引用与原始对象相同的对象:
class X
private:
int i;
int *pi;
public:
X()
: pi(new int)
X(const X& copy) // <-- copy ctor
: i(copy.i), pi(copy.pi)
;
这里,原始对象的pi
成员和复制的X
对象都将指向同一个int
。
深拷贝:
原始的所有成员都被克隆(如果需要,递归)。没有共享对象:
class X
private:
int i;
int *pi;
public:
X()
: pi(new int)
X(const X& copy) // <-- copy ctor
: i(copy.i), pi(new int(*copy.pi)) // <-- note this line in particular!
;
这里,原始和复制的X
对象的pi
成员将指向不同的int
对象,但它们具有相同的值。
默认的拷贝构造函数(如果你自己不提供,它会自动提供)只创建浅拷贝。
更正: 下面的几个 cmets 已经正确指出,说默认的复制构造函数 always 执行浅拷贝(或深拷贝)是错误的事情)。一个类型的拷贝构造函数是创建浅拷贝还是深拷贝,或者介于两者之间的东西,取决于每个成员的拷贝行为的组合;毕竟,成员类型的复制构造函数可以做任何它想做的事情。
以下是 1998 年 C++ 标准的第 12.8 节第 8 段对上述代码示例的说明:
隐式定义的副本 类
X
的构造函数执行一个 其子对象的成员副本。 [...] 每个子对象都复制到 适合其类型的方式:[...] [I]如果子对象是标量类型, 内置赋值运算符是 用过。
【讨论】:
神秘的段落似乎不同意您大胆声称默认复制构造函数仅生成浅拷贝。 是什么让你这么认为?我的理解如下:某些指针类型的成员是标量子对象,不是吗?如果你使用内置的赋值操作符复制一个指针,这意味着指向的对象不会被克隆,而只是被一个附加的指针引用。因此,您最终会得到一个浅拷贝。 @stakx 你是对的,但我认为这说明术语“深拷贝”和“浅拷贝”并不是特别有用——事实上,我从未听说有经验的 C++ 程序员使用它们。 默认的复制构造函数会生成一个member-wise的拷贝,而一个成员是深拷贝还是浅拷贝完全取决于成员的行为。struct Person string firstName, lastName;
- 默认复制构造函数进行 deep 复制。
所有可能的复制构造器“类型”的集合不包括 JUST “浅”和“深”的不相交集。它包括介于两者之间的所有内容(例如,一半的成员可能是浅拷贝,一半可能是深拷贝——但除非你知道他们的实现,否则你永远不会知道这些成员是在做浅拷贝还是深拷贝)。默认的复制构造函数既不总是“浅”也不总是“深”。浅层和深层这两个术语只是描述了可能的行为。【参考方案2】:
这方面的典型示例是指向结构或对象(可变)的指针数组。
浅拷贝复制数组并维护对原始对象的引用。
深拷贝也会复制(克隆)对象,因此它们与原始对象无关。这意味着对象本身被深度复制。这就是困难的地方,因为没有真正的方法可以知道某些内容是否被深度复制。
复制构造函数用于用之前创建的同一个类的对象来初始化新对象。默认情况下,编译器写了一个浅拷贝。当不涉及动态内存分配时,浅拷贝工作正常,因为当涉及动态内存分配时,两个对象将指向堆中的相同内存位置,因此为了解决这个问题,我们编写了深拷贝,因此两个对象都有自己的属性副本在记忆中。
要阅读包含完整示例和说明的详细信息,您可以查看文章Constructors and destructors。
默认的复制构造函数是浅的。您可以根据需要使自己的复制构造函数变深或变浅。见C++ Notes: OOP: Copy Constructors。
【讨论】:
它应该是一个指向可变对象的指针数组 一个很好的例子是 Boost::GIL,其中视图是图像对象(像素容器)的浅拷贝。当通过视图对象访问像素时,会生成像素的本地/临时副本。【参考方案3】:深拷贝实际上是执行深拷贝。这意味着,如果你的类有一些引用字段,它们的值将被复制,而不是引用本身。例如,如果您有一个类的两个实例,A 和 B 具有引用类型的字段,并执行深层复制,则更改 A 中该字段的值不会影响 B 中的值。反之亦然。浅拷贝的情况不同,因为只复制引用,因此,在复制的对象中更改此字段会影响原始对象。
复制构造函数执行什么类型的副本?
它依赖于实现。这意味着对此没有严格的规定,您可以像深拷贝或浅拷贝一样实现它,但是据我所知,在复制构造函数中实现深拷贝是一种常见的做法。不过,默认的复制构造函数会执行浅拷贝。
【讨论】:
以上是关于深拷贝与浅拷贝[重复]的主要内容,如果未能解决你的问题,请参考以下文章