C ++继承:缺少虚拟析构函数会导致内存泄漏吗?

时间:2015-12-28 12:58:06

标签: c++ memory virtual destructor

我对我经常问自己的一个问题表示怀疑,这就是情况:

两个类,没有虚拟析构函数

class Base
{
    int myInt;
};

class Derived : public Base
{
    int myIntDerived;
};

int main()
{
    Base    *base    = new Derived;
    Derived *derived = new Derived;

    delete base;
    delete derived;
}

说第一次删除会导致内存泄漏而第二次删除是否合适是不是正确?

2 个答案:

答案 0 :(得分:14)

  

说第一次删除会导致内存泄漏而第二次删除是否合适是不是正确?

第二个确实很好(虽然,你不想直接在真实程序中删除指针。一个人应该使用智能指针),但你的第一个语句并不完全正确。

正式地,通过指向具有非虚拟析构函数的基础子对象的指针删除对象具有未定义的行为。内存泄漏是可能的,但不是必需的。实际上,在您的情况下,由于derived及其任何成员对象都没有分配任何将在析构函数中释放的动态内存,因此可能不会发生泄漏。

当您的程序有未定义的行为时,内存是否泄露是您最不关心的问题。

答案 1 :(得分:10)

这是未定义的行为,实际上可能导致内存泄漏:
C ++标准,[expr.delete],第3段[ISO/IEC 14882-2014],声明:

  

在第一个备选(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为动态类型的基类。要删除的对象和静态类型应具有虚拟析构函数或行为未定义。在第二种方法(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为是未定义的。

由于BaseDerived中的析构函数都不是用户定义的,因此编译器会添加一个默认的析构函数。那些析构函数不是virtual

由于baseBase*delete base调用基类的析构函数,即未定义行为。具体而言,当您使用资源时,它会导致内存泄漏;在你的情况下,由于你的课程只包含POD,我会说没有泄漏。

为了修复内存泄漏,应该为要继承的类定义一个虚拟析构函数:

struct Base
{
    virtual ~Base() {}
    int myInt;
};

struct Derived : Base
{
    int myIntDerived;
};

int main()
{
    Base    *base    = new Derived;
    Derived *derived = new Derived;

    delete base;    // OK
    delete derived; // OK
}