非虚拟的简单析构函数+继承

时间:2011-05-11 20:55:48

标签: c++ inheritance destructor

假定一个类及其所有子类只需要默认的析构函数来释放它们的资源(如果存储在精确类型的变量中(或指向精确类型的指针)),如果由基类引用,子类是否会泄漏内存类指针然后被那个指针删除?

实施例

#include <memory>

class A {
};

class B : public A {
public:
    B () : pInt(new int) {}
    auto_ptr<int> pInt; // this is what might leak... possibly more will though
};

void will_this_leak () {
    A *pA = new B();
    delete pA;
}

4 个答案:

答案 0 :(得分:9)

“泄漏记忆”?你为什么要专门谈论泄漏记忆?

您发布的代码会产生未定义的行为。在这种情况下可能发生任何事情:内存泄漏,硬盘格式化,程序崩溃等等。

P.S。我知道那里有一个流行的都市传奇,在没有虚拟析构函数的情况下执行多态破坏“可能会泄漏内存”。我不知道是谁发明了那些废话以及为什么他们决定使用“泄漏记忆”作为可能发生的事情的主要场景。实际上,这种情况下的行为与“泄漏记忆”完全无关。行为很简单。

从实际的角度来看,在你的特定情况下很明显你的auto_ptr的析构函数没有真正的机会被调用,所以auto_ptr所拥有的内存肯定会被泄露。但同样,这是代码中最少的问题。

答案 1 :(得分:4)

它们是否可以泄漏并不重要。 C ++标准规定,如果基础没有虚拟析构函数,则通过基指针删除派生类是未定义的行为。具体来自5.3.5 / 3:

  

在第一个替代(删除对象)中,如果是静态类型的   操作数与其动态类型不同,静态类型应为   操作数的动态类型的基类和   静态类型应具有虚拟析构函数或行为未定义。

所以一旦你做了这样的删除,你的程序就处于一个未定义的状态,所有关于泄漏的问题都没有实际意义。

答案 2 :(得分:1)

是的,这会泄漏。当你删除A *时,它会调用~A()。由于~A()不是虚拟的,因此不会知道~B()也需要调用。

当然,假设B继承自A.我猜这是你问题中的错字 - 代码不能编译:)

答案 3 :(得分:1)

截至目前的代码展示 undefined-behavior

  

如果操作数的静态类型是   那么与动态类型不同   静态类型成为基类   它的析构函数必须是虚拟。否则行为未定义。

#include <memory>

class A {

    public :
    virtual ~A() {} // This makes the derived sub-object destruction first

};

class B : public A {
public:
    B () : pInt(new int) {}
    auto_ptr<int> pInt; 

    /* There is no need to write any custom destructor
       in this case. auto_ptr will effectively handle deallocating
       the acquired resources from free store.
    */
};

void will_this_leak () {
    A *pA = new B();
    delete pA;
}

通过上述更改,不应存在任何未定义的行为或内存泄漏。