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

StackOverflow https://stackoverflow.com/questions/677653

Вопрос

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

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

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

Из ответов я понял следующее (пожалуйста, отредактируйте, если это неправильно):

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

Решение

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

Другие советы

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

A * p = new A;

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

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

Внутри деструктора каждого класса вам необходимо удалить все остальные переменные-члены, выделенные с помощью 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 даже нет деструктора).

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

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

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

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

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

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

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

Нет, он не будет вызывать деструктор для класса А, вы должны назвать его явно (как сказал Poweroy), удалить линию «Удалить 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;
  }

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

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);

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top