指向子类的指针上的delete是否会调用基类析构函数?

时间:2009-03-24 14:30:33

标签: c++ memory-management destructor delete-operator base-class

我有一个class A,它为其中一个字段使用堆内存分配。 A类被实例化并存储为另一个类(class B

中的指针字段

当我完成了B类的一个对象时,我调用了delete,我假设它被称为析构函数......但这是否也会调用类A的析构函数?

编辑:

从答案中,我接受了(请编辑,如果不正确):

    B的实例的
  1. delete调用B ::〜B();
  2. 调用A::~A();
  3. A::~A 显式delete A对象的所有堆分配成员变量;
  4. 最后,将存储所述B类实例的内存块返回到堆中 - 当使用 new 时,它首先在堆上分配一块内存,然后调用构造函数来初始化它,现在之后已调用所有析构函数来最终确定对象所在的块返回堆的对象。

11 个答案:

答案 0 :(得分:179)

A的析构函数将在其生命周期结束时运行。如果您希望释放其内存并运行析构函数,则必须在堆上分配它时将其删除。如果它是在堆栈上分配的,则会自动发生(即当它超出范围时;参见RAII)。如果它是一个类的成员(不是指针,而是一个完整的成员),那么当包含对象被销毁时就会发生这种情况。

class A
{
    char *someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { delete[] someHeapMemory; }
};

class B
{
    A* APtr;
public:
    B() : APtr(new A()) {}
    ~B() { delete APtr; }
};

class C
{
    A Amember;
public:
    C() : Amember() {}
    ~C() {} // A is freed / destructed automatically.
};

int main()
{
    B* BPtr = new B();
    delete BPtr; // Calls ~B() which calls ~A() 
    C *CPtr = new C();
    delete CPtr;
    B b;
    C c;
} // b and c are freed/destructed automatically

在上面的示例中,需要每次删除和删除[]。在我没有使用它的情况下,不需要删除(或者确实可以使用)。

auto_ptrunique_ptrshared_ptr等......非常适合让这种终身管理变得更加轻松:

class A
{
    shared_array<char> someHeapMemory;
public:
    A() : someHeapMemory(new char[1000]) {}
    ~A() { } // someHeapMemory is delete[]d automatically
};

class B
{
    shared_ptr<A> APtr;
public:
    B() : APtr(new A()) {}
    ~B() {  } // APtr is deleted automatically
};

int main()
{
    shared_ptr<B> BPtr = new B();
} // BPtr is deleted automatically

答案 1 :(得分:29)

当你在new分配的指针上调用delete时,将调用指向的对象的析构函数。

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p

答案 2 :(得分:22)

它被命名为“析构函数”,而不是“解构函数”。

在每个类的析构函数中,您必须删除已使用new分配的所有其他成员变量。

编辑:澄清:

说你有

struct A {}

class B {
    A *a;
public:
    B () : a (new A) {}
    ~B() { delete a; }
};

class C {
    A *a;
public:
    C () : a (new A) {}        
};

int main () {
    delete new B;
    delete new C;
}

分配B的实例然后删除是干净的,因为B内部分配的内容也将在析构函数中删除。

但是C类的实例会泄漏内存,因为它会分配一个它不释放的A实例(在这种情况下C甚至没有析构函数)。

答案 3 :(得分:5)

如果你有一个通常的指针(A*)那么析构函数将不会被调用(并且A实例的内存也不会被释放),除非你在delete明确地{ {1}}的析构函数。如果你想要自动销毁,请查看B等智能指针。

答案 4 :(得分:4)

你应该在B的析构函数中删除A.

答案 5 :(得分:2)

class B
{
public:
    B()
    {
       p = new int[1024];  
    }
    virtual ~B()
    {
        cout<<"B destructor"<<endl;
        //p will not be deleted EVER unless you do it manually.
    }
    int *p;
};


class D : public B
{
public:
    virtual ~D()
    {
        cout<<"D destructor"<<endl;
    }
};

当你这样做时:

B *pD = new D();
delete pD;

只有在基类具有virtual关键字时才会调用析构函数。

然后,如果你没有虚拟析构函数,那么将调用B()。但是因为你有一个虚拟的析构函数,所以先调用~D(),然后调用~B()。

除非您明确删除它们,否则不会释放在堆上分配的B或D成员。删除它们也会调用它们的析构函数。

答案 6 :(得分:1)

我想知道为什么我的班级&#39;没有调用析构函数。原因是我忘了包含该类的定义(#include&#34; class.h&#34;)。我只有一个类似于&#34; A类的声明;&#34;并且编译器很满意它,让我打电话给#34;删除&#34;。

答案 7 :(得分:0)

没有。指针将被删除。你应该在B的析构函数中调用A的删除。

答案 8 :(得分:0)

只有在为该对象调用delete时,才会调用A类对象的析构函数。确保在B类的析构函数中删除该指针。

有关在对象上调用delete时会发生什么的更多信息,请参阅: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

答案 9 :(得分:0)

不,它不会为A类调用析构函数,你应该明确地调用它(比如PoweRoy告诉),删除行'delete ptr;'在示例中进行比较......

  #include <iostream>

  class A
  {
     public:
        A(){};
        ~A();
  };

  A::~A()
  {
     std::cout << "Destructor of A" << std::endl;
  }

  class B
  {
     public:
        B(){ptr = new A();};
        ~B();
     private:
        A* ptr;
  };

  B::~B()
  {
     delete ptr;
     std::cout << "Destructor of B" << std::endl;
  }

  int main()
  {
     B* b = new B();
     delete b;
     return 0;
  }

答案 10 :(得分:0)

你有类似

的东西
class B
{
   A * a;
}
B * b = new B;
b->a = new A;

如果您再调用delete b;,则没有任何操作,并且您有内存泄漏。试图记住delete b->a;不是一个好的解决方案,但还有其他几个。

B::~B() {delete a;}

这是B的析构函数,它将删除a。 (如果a为0,则删除不执行任何操作。如果a不为0但未指向new的内存,则会导致堆损坏。)

auto_ptr<A> a;
...
b->a.reset(new A);

这样你就没有指针,而是auto_ptr&lt;&gt; (shared_ptr&lt;&gt;也可以,或其他智能指针),当b为时,会自动删除。

这两种方法中的任何一种都很有效,我已经使用过它们。