class A {
....
};
class B: public A {
int x;
...
};
class C: public A{
A * ptr;
.....
};
class D : public A {
A* ptr1;
A* ptr2;
....
};
注意:我使B,C,D的所有构造函数都没有包含在那里。 所以A(没有字段)是超类,我有3个子类(B,C和D),每个子类都有不同的字段。
A是一个抽象类,它主要是Class(B,C,D)的链接
所以我可能会遇到像
这样的情况B *x = new B {5};
B *x2 = new B {5}
D * y = new D{x,x2);
所以,当我做delete y;
时,我想让它链式破坏它的两个字段的两个指针(B对象)。我如何为D类构造析构函数然后链式破坏?
就像我展示的示例非常简单,但其他示例有越来越多的图层。我想确保删除所有内容,以免发生内存泄漏。
我的D级Dtor应该是这样的吗?
~D(){
delete ptr1;
delete ptr2;
}
对于C类的情况,我会这样做吗?
~C(){
delete ptr;
}
因为我这样做并且它不起作用我得到内存泄漏所以什么是错的?
答案 0 :(得分:0)
我认为你的问题是错误的,因为你说它是一个继承链,但在撰写时B
,C
和D
直接来自A
。< / p>
当你new D
发生了什么事情时,你有一个由A
,B
,C
和D
组成的复合对象 - 它们是在继承中构建的顺序。
*y = {
// B starts
int x;
// C starts
A * ptr;
// D starts
A * ptr1;
A * ptr2;
};
请注意,析构函数将以相反的顺序调用,D
先调用C
,依此类推,以相反的顺序清理内存(处理超类的依赖关系)。但是,这取决于您要删除的对象类型。
如果我们这样做:
D * y = new D;
A * x = y;
delete x;
我们已将y
有效地视为A
对象,这意味着我们仅限于A
对象所知道的内容,并且只要我们使用{{1} }。如果我们使用x
删除,我们将调用x
而不是~A()
。这就是为什么在这种情况下析构函数需要是虚拟的,这允许~D()
调用virtual ~A()
,这将最终再次调用~D()
(真实的不是虚拟发货)。
无论您是否正在使用多态/上传,您的直觉都是正确的 - ~A()
应该只清理~D()
对象引入类的内存( D
和ptr1
)同样适用于ptr2
(仅~C()
)。
泄漏是因为对象切片发生在某处。例如(如果你强制这个编译),这比上面的例子更糟糕,因为不会复制对象数据(因为相对于被引用的对象的类型,结构定义是不完整的):
ptr
要非常小心,您只需将指针/引用传递给可能需要保存派生类型的对象,并确保使用虚拟析构函数。否则你正在做的是正确的,让每个类的析构函数只为该类清理。