Вызывает ли удаление указатель на подкласс деструктор базового класса?

У меня есть class A который использует выделение кучи памяти для одного из своих полей. Класс A создается и сохраняется как поле указателя в другом классе (class B

Когда я закончу с объектом класса B, я вызываю delete, который, как я полагаю, вызывает деструктор... Но вызывает ли это и деструктор класса A?

Редактировать:

Из ответов, я беру это (пожалуйста, измените, если неправильно):

  1. delete экземпляра B вызывает B :: ~ B();
  2. который вызывает A::~A();
  3. A::~A должен явно delete все выделенные в куче переменные-члены объекта A;
  4. Наконец, блок памяти, хранящий указанный экземпляр класса B, возвращается в кучу - когда использовался new, он сначала выделял блок памяти в куче, затем вызывал конструкторы для его инициализации, теперь после того, как все деструкторы были вызваны для завершения объекта, блок, в котором находился объект, возвращается в кучу.

Ответ 1

Деструктор 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_ptr, unique_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

Ответ 2

Когда вы вызываете delete на указателе, выделенном new, вызывается деструктор объекта, на который указывает.

A * p = new A;

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

Ответ 3

Он называется "деструктор", а не "deconstructor".

Внутри деструктора каждого класса вам нужно удалить все остальные переменные-члены, которые были назначены новым.

Изменить: Чтобы уточнить:

Скажите, что у вас

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 даже не имеет деструктора).

Ответ 4

Если у вас есть обычный указатель (A*), деструктор не будет вызван (и память для экземпляра A тоже не будет освобождена), если вы явно не выполняете delete в B деструкторе. Если вы хотите автоматическое уничтожение, посмотрите на интеллектуальные указатели, такие как auto_ptr.

Ответ 5

Вы должны удалить A самостоятельно в деструкторе B.

Ответ 6

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, выделенные в куче, не будут освобождены, если вы их явно не удалите. И удаление их также вызовет их деструктор.

Ответ 7

Мне было интересно, почему мой деструктор класса не был вызван. Причина в том, что я забыл включить определение этого класса (#include "class.h" ). У меня было только объявление типа "класс А"; и компилятор был доволен этим, и позвольте мне называть "удалить".

Ответ 8

Нет. указатель будет удален. Вы должны вызвать delete в явным образом в деструкторе B.

Ответ 9

Деструктор для объекта класса A будет вызываться только в том случае, если для этого объекта вызывается delete. Обязательно удалите этот указатель в деструкторе класса B.

Для получения дополнительной информации о том, что происходит при вызове delete для объекта, см. http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

Ответ 10

no, он не будет вызывать деструктор для класса 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;
  }

Ответ 11

У вас есть что-то вроде

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, но не указывает на память от нового, вы получаете повреждение кучи.)

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

Таким образом, у вас нет указателя, а auto_ptr < > (shared_ptr < > будет делать также или другие интеллектуальные указатели), и он автоматически удаляется, когда b.

Любой из этих способов работает хорошо, и я использовал оба.