3
#include <iostream> 
using namespace std; 
class c1 {}; 
class c2 : public c1 {}; 
class c3 : public c1 {}; 
class c4 : public c2, public c3 {}; 

int main() { 
    c4 *x1 = new c4; 
    c3 *x2 = x1; 
    delete x2; // segmentation fault 
} 

嗨,我想了解类型转换和继承,我发现这个问题。我有一个指向最派生的类,并指定(隐式)中间任何类,同时删除,我认为它应该能够删除第一个新分配的空间。在一些编译器中,它看起来很好,但在linux gcc 4.7.2版(Debian 4.7.2-5)中,它给出了分段错误。无法弄清楚,为什么?任何帮助/指针/建议将不胜感激。分段错误删除指针

注 - 类是以钻石问题的形式派生的。

+1

你应该在c3中实现虚拟析构函数。 – Zefick

+0

这不是钻石问题,因为没有虚拟继承。 c4类实际上有两个c1实例。 – Zefick

+0

谢谢。我正在阅读更多关于虚拟析构函数的用法。 –

回答

3

这是未定义的行为。正如你所看到的,在某些情况下它可能看起来很好,在某些情况下它不会。

至少基类c3(或c1c2)应具有虚拟析构函数。例如

class c3 : public c1 { 
public: 
    virtual ~c3() {} 
}; 

根据标准,$5.3.5/3 Delete [expr.delete]

(重点煤矿)

在第一种方式(删除对象),如果 对象的静态类型要被删除不同于它的动态类型,静态的 类型应该是动态类型的对象的基类,将 删除,静态类型应该具有虚拟析构函数或 行为未定义

2

试图删除未由new返回的指针。对于基础类的解决方案使用virtual destructor。当通过指向基类的指针删除对象时,基类需要一个virtual析构函数。

1

要添加到以前的答案,在undefined行为来自于一个事实,即铸造的指针指向一个基类机构(大部分的时间,而不是在你的例子)切片:指针被调整(即递增)指向嵌入类的开始。

因此,在增加的指针上调用delete时,可能会释放部分内存,并让其中的一部分悬空