简体   繁体   English

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

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

I wonder when C++ does deep copying, and when it does shallow copying. 我想知道C ++何时进行深度复制,何时进行深度复制。

For example: 例如:

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

In order to delete n after moving out of the function, it must create a temporary variable n, and return it back to the caller. 为了在移出函数后删除n,它必须创建一个临时变量n,并将其返回给调用方。 As a result, that's shallow copy, is that right? 结果,那是浅表副本,对吗?

As a result, that's shallow copy, is that right? 结果,那是浅表副本,对吗?

A shallow copy keeps referring to whatever the original object referred to. 浅表副本始终引用原始对象†所引用的内容。 A deep copy refers to a copy of the referred resource †† (this new copy of the resource must be created by the copy constructor). 深层副本是指所引用资源的副本†† (该资源的新副本必须由副本构造函数创建)。 That distinction is meaningful only if the copied object is referential ie it refers to some resource. 仅当复制的对象是引用对象(即它引用某种资源)时,这种区别才有意义。

int type does not refer to any object, so as far as the type system is concerned, it is not referential. int类型不引用任何对象,因此就类型系统而言,它不是引用的。 However outside of the type system, one can give it referential meaning. 但是在类型系统之外,可以给它提供参考意义。 It is quite typical for example, for an integer to represent identity of a resource such as an entity stored in a database. 例如,用整数表示资源(例如存储在数据库中的实体)的身份是非常典型的。 You need to consider whether that is the case for your integer. 您需要考虑整数是否是这种情况。 In object oriented design, such identifiers are typically wrapped into a class ††† (which can be specified to support deep copies). 在面向对象的设计中,此类标识符通常包装在†††类中(可以指定为支持深层副本)。

The copy of a non-class type is always shallow. 非类类型的副本总是浅的。 Only copy constructor †††† can perform a deep copy. 只有复制构造函数††††可以执行深层复制。 If 5 identifies some resource, then a copy of 5 also refers to that same resource. 如果5标识某个资源,则5的副本也引用该相同资源。

Examples of referential types for which deep and shallow copy are relevant: References, pointers, classes which have referential members. 与深层复制和浅层复制相关的引用类型的示例:引用,指针,具有引用成员的类。 Examples of usch classes: smart pointers, wrappers of referential identifiers ††† . usch类的示例:智能指针,引用标识符的包装††† Of these, pointers and references are copied shallowly, since they aren't classes. 在这些指针和引用中,它们不是类,因此会被浅表复制。 Copy of a class instance may be shallow or deep, depending on the implementation of the copy constructor. 根据复制构造函数的实现,类实例的复制可能浅或深。

Then there is move construction. 然后是搬家建筑。 Move construction is a shallow copy, which modifies the original object in a way that enforces any class invariants that would be violated by a trivial shallow copy. 移动构造是一个浅表副本,它以强制任何平凡的浅表副本会违反的类不变式的方式修改原始对象。 For example, the move constructor of a unique pointer would shallowly copy the internal pointer, and set the original pointer to null, so that the uniqueness of pointer ownership is maintained. 例如,唯一指针的move构造函数将浅表复制内部指针,并将原始指针设置为null,以便保持指针所有权的唯一性。


I say object for simplicity, but this applies to copies of a reference types - which are not objects - too. 我说的是对象是为了简单起见,但这也适用于引用类型的副本-也不是对象。

†† A resource might be another object in memory, or for example a file descriptor, or a thread of execution. ††资源可能是内存中的另一个对象,例如文件描述符或执行线程。

††† Example: std::thread which wraps a lower level identifier provided by the OS. †††示例: std::thread ,它包装操作系统提供的较低级别的标识符。

†††† Any function can perform a deep copy, but a copy constructor is the only function that is invoked by copy initialisation. ††††任何函数都可以执行深层复制,但复制构造函数是唯一由复制初始化调用的函数。

int is not a referential type and so there is no question of shallow or deep copy. int不是引用类型,因此没有浅拷贝或深拷贝的问题。 Its just a copy. 它只是一个副本。

We can understand Deep and shallow copy as follows : 我们可以理解深度复制和浅层复制,如下所示:

Deep Copy 深拷贝

A deep copy copies all fields, and makes copies of dynamically allocated memory pointed to by the fields. 深层副本将复制所有字段,并复制这些字段所指向的动态分配的内存。 A deep copy occurs when an object is copied along with the objects to which it refers. 当将对象及其引用的对象一起复制时,将发生深层复制。

Shallow Copy 浅拷贝

Shallow copy is a bit-wise copy of an object. 浅拷贝是对象的按位拷贝。 A new object is created that has an exact copy of the values in the original object. 创建一个新对象,该对象具有原始对象中值的精确副本。 If any of the fields of the object are references to other objects, just the reference addresses are copied ie, only the memory address is copied, not the actual objects. 如果对象的任何字段是对其他对象的引用,则仅复制参考地址,即仅复制内存地址,而不复制实际对象。

The terms "shallow copy" and "deep copy" are generally understood to relate to types that themselves indirectly encapsulate some objects. 术语“浅拷贝”和“深拷贝”通常被理解为涉及自身间接封装某些对象的类型。

So, for example, a class with a pointer (that we assume points to something): 因此,例如,一个带有指针的类(我们假设它指向某物):

struct Foo
{
   Bar* ptr;
};

When you copy a Foo , is the Bar it points to copied as well ( deep )? 复制Foo ,它是否也指向复制的Bar深层 )? Or does the new Foo merely share the original pointer to the original Bar ( shallow )? 还是新的Foo仅仅共享指向原始Bar )的原始指针?

This will depend upon how the copy is performed — usually your Foo will have a copy constructor, and it is the code in this copy constructor that makes the distinction. 这将取决于复制的执行方式-通常,您的Foo将具有一个复制构造函数,而正是这个复制构造函数中的代码才有区别。

For example, all standard C++ containers (eg vector ) are internally made up of a bunch of pointers to some allocated buffers, but they have copy constructors that ensure the whole buffer is copied when the vector is copied, so that each vector has its own , independent buffer. 例如,所有标准C ++容器(例如vector )在内部都是由指向一些已分配缓冲区的指针组成的,但是它们具有复制构造函数,可确保在复制矢量时复制整个缓冲区,以便每个矢量都有其自己的 ,独立缓冲区。 This is a deep copy. 这是一个深复制。

But the example I gave above, without any copy constructor or other lovely code, will simply perform a shallow copy when assigned, because I didn't tell it to do anything except to copy over the value of ptr . 但是我上面给出的示例,没有任何复制构造函数或其他可爱的代码,在分配时将仅执行浅表复制,因为除了复制ptr的值外,我没有告诉它做任何事情。

As for your case: an int is just a value and so we can make no such comparison. 至于您的情况: int只是一个值,因此我们无法进行这种比较。 You just have a value copy, plain and simple. 您只有简单而简单的值副本。 The internal details of how many (if any) temporaries are required to implement that functionality are irrelevant (and unimportant); 实现该功能需要多少个临时人员的内部细节是无关紧要的(无关紧要); it's meaningless to talk about shallow vs deep copies in this case because there is literally no encapsulated, indirectly-held object owned or not-owned that can be deemed shallow or deep or anything copied. 在这种情况下,谈论浅副本与深副本是没有意义的,因为从字面上看,没有封装的,间接拥有的对象拥有或不拥有的对象,可以被视为浅或深的副本或任何复制的对象。 And we can generally say this about any non-class type. 我们通常可以对任何非类类型说这句话。

Your description of the behaviour of your code is consistent with the source code that you present but the compiler might not do that. 您对代码行为的描述与您提供的源代码一致,但是编译器可能不会这样做。

C++ compilers are allowed to implement an as-if rule: ie your source specifies your intentions not the form of the final executable. 允许C ++编译器实现一个按条件规则:即,您的源代码指定的是您的意图,而不是最终可执行文件的形式。

In other words, the compiler could replace your entire function call with 5 . 换句话说,编译器可以将整个函数调用替换为5

In short, a deep copy creates duplicates every byte in your source object that's pertinent to that object. 简而言之, 深层副本会在源对象中与该对象相关的每个字节中创建一个副本。 Any lesser copy than that is a shallow copy. 小于此的任何副本都是副本。 Unless you overload = in some way, = takes a shallow copy. 除非以某种方式重载= ,否则=将获取浅表副本。

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

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