繁体   English   中英

C ++何时执行深层复制和浅层复制?

[英]When does C++ perform deep copying and shallow copying?

我想知道C ++何时进行深度复制,何时进行深度复制。

例如:

int find()
{
    int n=5;
    return n;
}

为了在移出函数后删除n,它必须创建一个临时变量n,并将其返回给调用方。 结果,那是浅表副本,对吗?

结果,那是浅表副本,对吗?

浅表副本始终引用原始对象†所引用的内容。 深层副本是指所引用资源的副本†† (该资源的新副本必须由副本构造函数创建)。 仅当复制的对象是引用对象(即它引用某种资源)时,这种区别才有意义。

int类型不引用任何对象,因此就类型系统而言,它不是引用的。 但是在类型系统之外,可以给它提供参考意义。 例如,用整数表示资源(例如存储在数据库中的实体)的身份是非常典型的。 您需要考虑整数是否是这种情况。 在面向对象的设计中,此类标识符通常包装在†††类中(可以指定为支持深层副本)。

非类类型的副本总是浅的。 只有复制构造函数††††可以执行深层复制。 如果5标识某个资源,则5的副本也引用该相同资源。

与深层复制和浅层复制相关的引用类型的示例:引用,指针,具有引用成员的类。 usch类的示例:智能指针,引用标识符的包装††† 在这些指针和引用中,它们不是类,因此会被浅表复制。 根据复制构造函数的实现,类实例的复制可能浅或深。

然后是搬家建筑。 移动构造是一个浅表副本,它以强制任何平凡的浅表副本会违反的类不变式的方式修改原始对象。 例如,唯一指针的move构造函数将浅表复制内部指针,并将原始指针设置为null,以便保持指针所有权的唯一性。


我说的是对象是为了简单起见,但这也适用于引用类型的副本-也不是对象。

††资源可能是内存中的另一个对象,例如文件描述符或执行线程。

†††示例: std::thread ,它包装操作系统提供的较低级别的标识符。

††††任何函数都可以执行深层复制,但复制构造函数是唯一由复制初始化调用的函数。

int不是引用类型,因此没有浅拷贝或深拷贝的问题。 它只是一个副本。

我们可以理解深度复制和浅层复制,如下所示:

深拷贝

深层副本将复制所有字段,并复制这些字段所指向的动态分配的内存。 当将对象及其引用的对象一起复制时,将发生深层复制。

浅拷贝

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

术语“浅拷贝”和“深拷贝”通常被理解为涉及自身间接封装某些对象的类型。

因此,例如,一个带有指针的类(我们假设它指向某物):

struct Foo
{
   Bar* ptr;
};

复制Foo ,它是否也指向复制的Bar深层 )? 还是新的Foo仅仅共享指向原始Bar )的原始指针?

这将取决于复制的执行方式-通常,您的Foo将具有一个复制构造函数,而正是这个复制构造函数中的代码才有区别。

例如,所有标准C ++容器(例如vector )在内部都是由指向一些已分配缓冲区的指针组成的,但是它们具有复制构造函数,可确保在复制矢量时复制整个缓冲区,以便每个矢量都有其自己的 ,独立缓冲区。 这是一个深复制。

但是我上面给出的示例,没有任何复制构造函数或其他可爱的代码,在分配时将仅执行浅表复制,因为除了复制ptr的值外,我没有告诉它做任何事情。

至于您的情况: int只是一个值,因此我们无法进行这种比较。 您只有简单而简单的值副本。 实现该功能需要多少个临时人员的内部细节是无关紧要的(无关紧要); 在这种情况下,谈论浅副本与深副本是没有意义的,因为从字面上看,没有封装的,间接拥有的对象拥有或不拥有的对象,可以被视为浅或深的副本或任何复制的对象。 我们通常可以对任何非类类型说这句话。

您对代码行为的描述与您提供的源代码一致,但是编译器可能不会这样做。

允许C ++编译器实现一个按条件规则:即,您的源代码指定的是您的意图,而不是最终可执行文件的形式。

换句话说,编译器可以将整个函数调用替换为5

简而言之, 深层副本会在源对象中与该对象相关的每个字节中创建一个副本。 小于此的任何副本都是副本。 除非以某种方式重载= ,否则=将获取浅表副本。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM