为什么调用Base类析构函数会导致此程序崩溃?

时间:2015-02-26 22:25:28

标签: c++

class ParentClass {
protected:
    int* intArray;

public:
    ~ParentClass(){
        delete [] intArray;
    }
};

class ChildClass : public ParentClass {
public:
    ChildClass() : ParentClass() {
        intArray = new int[5];
    }
};

int main(int argc, const char * argv[]) {
    ChildClass child;
    child.~ChildClass(); //This line crashes the program. why??
}

它抛出的具体错误: 初始化(37640,0x7fff78623300)malloc: *对象0x100100aa0的错误:释放的指针未分配 * 在malloc_error_break中设置断点以进行调试

指针引用intArray中声明的ParentClass,错误表明内存未分配,但它是在ChildClass构造函数中分配的。

有人可以解释生成此错误的过程吗?

3 个答案:

答案 0 :(得分:2)

问题不在于intArray未分配,而是您要将其解除分配两次。

ChildClass child;实例化ChildClass实例并调用默认构造函数,该构造函数分配intArray很好,没问题。

然后您的代码显式调用析构函数(对于堆栈分配/自动对象,您通常不需要这样做。)

然后编译器在范围清理期间向析构函数插入另一个调用,这会导致第二次调用delete[],这是不正确的,并导致崩溃。您的调试器可能会报告该函数的最后一行(显式析构函数调用的位置),它应该指向右括号。

可以肯定的是,在析构函数中设置断点并运行程序,看看它被击中的次数。

答案 1 :(得分:1)

您遇到了未定义的行为。来自C ++标准:

  

为对象调用析构函数后,该对象不再存在;如果是,行为是不确定的   为生命周期结束的对象调用析构函数(3.8)。 [例如:如果析构函数是自动的   显式调用object,然后以通常的方式保留块   调用对象的隐式销毁,行为未定义。

答案 2 :(得分:0)

childmain()的本地对象。离开功能范围时会自动销毁。

不幸的是,在通过显式调用析构函数离开函数之前手动销毁它。所以它被摧毁了两次(一次太多):第二次它崩溃了!

您不必销毁本地对象。当您使用new动态分配对象时,只需要指针进行显式破坏。但是你应该使用delete删除它们。

析构函数的显式调用仅在极少数情况下相关:当您想要使用 placement-new 重用动态对象的存储时。

备注: ParentClass您应该将intArray初始化为nullptr。这将确保如果不小心不进行分配,delete将不会尝试释放一个惯性指针。