【问题标题】:C++ inheritance: does lack of virtual destructor lead to memory leak? [duplicate]C ++继承:缺少虚拟析构函数会导致内存泄漏吗? [复制]
【发布时间】:2016-04-02 07:54:00
【问题描述】:

我对一个经常问自己的问题有一个疑问,就是这种情况:

两个类,没有虚析构函数

class Base
{
    int myInt;
};

class Derived : public Base
{
    int myIntDerived;
};

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

    delete base;
    delete derived;
}

说第一次删除会导致内存泄漏,第二次正常吗?

【问题讨论】:

  • 在实践中,一切正常,没有内存泄漏。从理论上讲,这是未定义的行为,任何事情都可能发生。实际上,当Derived 拥有单独分配的内存时,您所询问的那种内存泄漏就会发生。

标签: c++ memory virtual destructor


【解决方案1】:

说第一次删除会导致内存泄漏,第二次正常吗?

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

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

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

【讨论】:

  • 为什么这被否决了?答案准确而完整。
  • @KerrekSB 我猜生活是不公平的。我们只能通过投票来补偿。
【解决方案2】:

这是未定义的行为,确实可能导致内存泄漏:
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
}

【讨论】:

    猜你喜欢
    • 2019-11-09
    • 2012-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多