170

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

当我处理完 B 类的对象后,我调用delete,我假设它调用了析构函数……但这是否也调用了 A 类的析构函数?

编辑:

从答案中,我认为(如果不正确,请编辑):

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

11 回答 11

188

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

在上面的例子中,每个 delete 和 delete[] 都是需要的。在我没有使用它的地方不需要删除(或者确实可以使用)。

auto_ptrunique_ptr等等shared_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
于 2009-03-24T14:32:33.683 回答
32

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

A * p = new A;

delete p;    // A:~A() called for you on obkect pointed to by p
于 2009-03-24T14:36:11.647 回答
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 甚至没有析构函数)。

于 2009-03-24T14:32:22.797 回答
5

如果你有一个通常的指针 ( A*) ,那么析构函数将不会被调用(A例如内存也不会被释放),除非你在的析构函数delete中明确地这样做。B如果您想要自动销毁,请查看智能指针,例如auto_ptr.

于 2009-03-24T14:34:39.437 回答
4

您应该在 B 的析构函数中自己删除 A。

于 2009-03-24T14:33:55.210 回答
4
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 的任何成员都不会被释放。删除它们也会调用它们的析构函数。

于 2009-03-24T14:34:03.323 回答
1

你有类似的东西

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

如果您然后调用delete b;,则 a 不会发生任何事情,并且您有内存泄漏。试图记住delete b->a;不是一个好的解决方案,但还有其他几个。

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

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

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

这样你就没有 a 作为指针,而是一个 auto_ptr<> (shared_ptr<> 也可以,或者其他智能指针),当 b 是时它会被自动删除。

这两种方法中的任何一种都很好用,我都用过。

于 2009-03-24T15:00:40.077 回答
1

我想知道为什么我的班级的析构函数没有被调用。原因是我忘记包含该类的定义(#include "class.h")。我只有一个像“A级”这样的声明;编译器对此很满意,让我称之为“删除”。

于 2017-08-17T12:29:43.397 回答
0

不,指针将被删除。您应该在 B 的析构函数中显式调用 A 上的删除。

于 2009-03-24T14:32:13.077 回答
0

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

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

于 2009-03-24T14:35:15.533 回答
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;
  }
于 2009-03-24T14:50:35.077 回答