深度复制包含引用成员的结构(C+;+;) 我有C++类,它包含指向指向类内其他对象的引用成员的对象。这在当时似乎是个好主意,但现在我需要实现整个过程的深层次复制,我看不到一种不让人觉得笨拙的方法
我的代码的简化版本如下所示。问题在于为深度复制包含引用成员的结构(C+;+;) 我有C++类,它包含指向指向类内其他对象的引用成员的对象。这在当时似乎是个好主意,但现在我需要实现整个过程的深层次复制,我看不到一种不让人觉得笨拙的方法,c++,deep-copy,C++,Deep Copy,我的代码的简化版本如下所示。问题在于为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 {
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
};
有几个人问过这个结构是如何初始化的,所以请允许我强调,这与回答这个问题无关。初始化将始终满足b_数组
中项目的参考成员指向c_数组
中项目的要求,但除此之外,数据可以是任何内容。复制构造函数对满足此属性的任何数据都有效,这一点很重要。这不是一个可以通过重用现有初始化代码来解决的问题
问题是,如果我只是复制b_数组中的对象,它们的引用成员将指向A
的旧实例中的C
对象。我需要让它们指向新实例中的相应项。我能想到的唯一方法是:
- 对于
b_数组的每个元素
,获取其引用成员指向的地址,并将其存储在指针中
- 使用指针算法计算该指针对应的数组的索引
- 使用此索引初始化新
b_数组的相应元素的引用成员
我的问题是,有没有更干净/更简单/更优雅的方法?如果没有,我将重构我的设计,使用数组索引而不是引用
也许我不应该使用参考成员——我知道有些人说使用指针总是更好的。如果我使用指针而不是引用,这个问题会有更好的解决方案吗?(我看不到,但我不知道。)使用引用的深度复制必须首先复制值(c_数组),然后存储对这些新值的引用。除了您描述的算法之外,我看不到实现这一点的方法
使用指针而不是引用不会改变这一点。有很多种。指针初始化起来不那么棘手(创建为null并在准备就绪时赋值),使用起来更危险(可能仍然为null)。但是您仍然需要复制对象,然后查找并复制指向它们的链接
我看不到比使用数组索引更简单/更优雅的方法。使用数组索引,您只需按值复制数组值,并且索引的结构指向将为您处理的对象。您可以为a
提供赋值运算符(和复制选择器),该运算符处理c_数组
和b_数组
的串联更改,假设B
可以将C
的赋值处理为引用/指针更新
它可以是以下几点:
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;
}
};
有点乱,但是:
请注意,如果您注释掉std::copy_n
行,您当然可以在输出中观察到副本没有分离,也就是说,副本的b_数组
指向原始的c_数组
,而不是它自己的。有趣的问题!我看到的所有“深度复制”问题在编译时都有已知的引用结构,并在复制逻辑中进行了硬编码。能否用一个映射替换b_数组和c_数组?@GrahamGriffiths我的实际b
类存储对c_数组
成员的多个引用。我想它可以实现为几个map
s,但是真正的B
是一个实现其他代码的类层次结构,因此重新考虑会有点棘手。(我也倾向于避免使用STL代码,我想这主要是出于习惯。)如果不了解当前如何初始化这些数组,就很难给出任何具体的建议,即复制构造函数需要初始化副本,并且您有一些现有的代码来初始化原件。所有重要的细节都在评论中一点一滴地出现,这使得人们很难猜测解决方案需要提供什么,或者现有的解决方案是什么(未显示)代码它可以重用数组索引的唯一问题是,如果我将c_array
替换为更易变的东西,如std::list
,那么当其内容更改时,所有索引都必须更新,如果它们不同步,则很难跟踪错误。(目前我的代码没有做到这一点,但我可能很想在将来做到。)当然,我现在看到,基于引用成员的实现也有引入滑错误的方法。你的答案可能是对的,但如果有人有一个聪明的解决方案,我会保留它。我认为指针算法比std::find
好,因为std::find
必须进行线性搜索,而指针算法可以在一次操作中告诉我答案。我已经有了内存地址,所以我不需要搜索元素,只要从c\u数组指针的值中减去它就行了。谢谢,这是个好主意,但不幸的是,在我的情况下,这是不可能的,因为B
包含对ac
的多个引用以及其他数据。(我曾试图将问题简化为最简单的版本,但现在我意识到我应该明确指出,B
包含其他数据-我已经更新了问题中的示例代码。对此表示抱歉。)可以理解,B
包含其他数据,但这正是B
的普通赋值运算符和复制构造函数的作用。我的观点是,在您实现了op和copy-ctor之后,再进行一些后续操作