简体   繁体   English

深度复制包含引用成员的结构(C ++)

[英]Deep-copying a structure containing reference members (C++)

I have a C++ class that contains objects that have reference members pointing to other objects within the class. 我有一个C ++类,其中包含对象,这些对象的引用成员指向该类中的其他对象。 This seemed like a good idea at the time, but now I need to implement a deep copy of the whole thing, and I can't see a way to do that that doesn't feel like a clunky hack. 当时这似乎是个好主意,但现在我需要对整个过程进行深层复制,而且我看不出有什么办法像笨拙的hack一样。

A simplified version of my code looks like this. 我的代码的简化版本如下所示。 The question is about writing a copy constructor for A . 问题是关于为A编写副本构造函数。

class C {
    int x, y, z; // nothing complicated stored in this class
public:
    // constructor and other methods
};

class B {
    C &c1;
    C &c2;
public:
    // constructor and other methods
};

class A {
    C *c_array;
    B *b_array; // for each item in this array, 
                // its 'c1' and 'c2' fields point to members of c_array.
public:
    // constructor and other methods
};

A few people have asked how this structure is initialised, so please let me stress that this is irrelevant for answering the question. 一些人问过这种结构是如何初始化的,所以请让我强调,这与回答这个问题无关。 The initialisation will always satisfy the requirement that the reference members of the items in b_array point to items in c_array , but beyond that the data could be anything. 初始化将始终满足b_array中的项的引用成员指向b_array中的项的c_array ,但除此之外,数据可以是任何东西。 It is important that the copy constructor work for any data that satisfies this property. 对于所有满足此属性的数据,复制构造函数都必须工作,这一点很重要。 This is not a problem that can be solved by reusing the existing initialisation code. 这不是可以通过重新使用现有的初始化代码来解决的问题。

The problem is that if I just copy the objects in b_array , their reference members will point to the C objects in the old instance of A . 问题是,如果仅复制b_array的对象,则它们的引用成员将指向A实例中的C对象。 I need to make them point to the corresponding items in the new instance. 我需要使它们指向实例中的相应项目。 The only way I can think to do that is this: 我能想到的唯一方法是:

  • for each element of b_array , get the address that its reference member points to, and store that in a pointer 对于b_array每个元素,获取其引用成员指向的地址,并将其存储在指针中

  • work out the index into the array that that pointer corresponds to using pointer arithmetic 使用指针算术算出该指针对应的数组索引

  • use this index to initialise the reference member of the corresponding element of the new b_array . 使用该索引初始化新b_array的相应元素的引用成员。

My question is, is there a cleaner / simpler / more elegant way? 我的问题是, 是否有一种更清洁/更简单/更优雅的方式? If there isn't, I will just refactor my design to use array indices instead of references throughout. 如果没有,我将重构我的设计以使用数组索引而不是整个引用。

Perhaps I shouldn't have used reference members - I know some people say it's always better to use pointers. 也许我不应该使用引用成员-我知道有人说使用指针总是更好。 If I had used pointers instead of references, would there be a better solution to this problem? 如果我使用指针而不是引用,是否有更好的解决方案? (I can't see one but I don't know.) (我看不到,但我不知道。)

A deep copy using references will have to first copy the values (c_array) and then store references to those new values. 使用引用的深层副本必须首先复制值(c_array),然后将引用存储到这些新值。 I cannot see a way of achieving this other than the algorithm you describe. 除了您描述的算法外,我看不到其他实现方法。

Using pointers instead of references will not change this. 使用指针而不是引用不会更改此设置。 There are various comparisons of pointers vs references . 指针与引用之间有各种比较 Pointers are less tricky to initialise (create as null and assign when you are ready) and more dangerous to use (might still be null). 指针初始化起来比较麻烦(创建为null并在准备好时分配),使用起来更加危险(可能仍然为null)。 But you will still have to copy the objects, then find + copy the links to them. 但是您仍然必须复制对象,然后找到+复制指向它们的链接。

I cannot see a simpler / more elegant way than using array indices. 我看不到比使用数组索引更简单/更优雅的方法。 With array indices you will just copy the arrays value by value, and the structure of which index points to which object will be taken care of for you. 使用数组索引,您只需按值复制数组的值,以及索引结构将指向您要照顾的对象。

You can provide an assignment operator (and a copy ctor) for A that deals with the change of both c_array and b_array in tandem, assuming that B can handle the assignment of C as just a reference/pointer update. 您可以为A提供一个赋值运算符(和副本ctor), A运算符串联处理c_arrayb_array的更改,假设B可以将C的赋值仅作为参考/指针更新来处理。

It can be along the lines of: 可以遵循以下原则:

struct B { ... B& operator=(const C& c) { this->c = &c; return *this; } };

struct A { ...
    A& operator=(const A& a) {
        c_array = a.c_array;
        b_array = a.b_array;
        // re-assign pointers/references only using B's `operator=(const C&)` :
        std::copy_n(c_array.begin(), c_array.size(), b_array.begin());
        return *this;
    }
};

A bit messy, but: see live example 有点混乱,但是: 请看现场示例

Note that if you comment out the std::copy_n line, you can of course observe in the output that the copy isn't detached, that is, the b_array of the copy points to the original's c_array instead of its own. 请注意,如果您注释掉std::copy_n行,当然你也可以观察到,该副本是不沾边的输出,也就是b_array复制指向原始的的c_array ,而不是自己的。

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

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