web-dev-qa-db-fra.com

La suppression sur un pointeur vers une sous-classe appelle-t-elle le destructeur de classe de base?

J'ai un class A qui utilise une allocation de mémoire heap pour l'un de ses champs. La classe A est instanciée et stockée en tant que champ de pointeur dans une autre classe (class B.

Lorsque j'ai terminé avec un objet de classe B, j'appelle delete, qui, je suppose, appelle le destructeur ... Mais cela appelle-t-il également le destructeur de la classe A?

Modifier:

À partir des réponses, je prends cela (éditez s'il vous plaît si incorrect):

  1. delete d'une instance de B appelle B :: ~ B ();
  2. qui appelle A::~A();
  3. A::~Adevrait explicitement delete toutes les variables de membre allouées par tas de l'objet A;
  4. Enfin, le bloc de mémoire stockant ladite instance de classe B est renvoyé au segment de mémoire. Lorsque nouvea était utilisé, il affectait d’abord un bloc de mémoire sur la section de mémoire, puis appelait les constructeurs pour l’initialiser, à présent après que tous les destructeurs eurent terminé. été appelé pour finaliser l'objet, le bloc dans lequel il réside est renvoyé au tas.
161
Nick Bolton

Le destructeur de A s'exécutera à la fin de sa durée de vie. Si vous voulez que sa mémoire soit libérée et que le destructeur soit exécuté, vous devez le supprimer s'il a été alloué sur le tas. Si elle a été allouée sur la pile, cela se produit automatiquement (c’est-à-dire qu’elle sort du domaine; voir RAII). S'il s'agit d'un membre d'une classe (pas un pointeur, mais un membre à part entière), cela se produira lorsque l'objet contenant est détruit.

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

Dans l'exemple ci-dessus, chaque suppression et suppression [] est nécessaire. Et aucune suppression n'est nécessaire (ni même utilisable) là où je ne l'ai pas utilisée.

auto_ptr, unique_ptr et shared_ptr etc ... sont parfaits pour faciliter la gestion de la durée de vie:

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
180
Eclipse

Lorsque vous appelez delete sur un pointeur alloué par new, le destructeur de l'objet pointé sera appelé.

A * p = new A;

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

Il s'appelle "destructeur", pas "déconstructeur".

Dans le destructeur de chaque classe, vous devez supprimer toutes les autres variables membres qui ont été allouées avec new.

edit: Pour clarifier:

Dis que tu as

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

L'affectation d'une instance de B puis la suppression sont propres, car ce que B alloue en interne sera également supprimé du destructeur.

Mais les instances de classe C perdront de la mémoire, car elles allouent une instance de A qu’elle ne libère pas (dans ce cas, C n’a même pas de destructeur).

22
Sebastian Mach

Si vous avez un pointeur habituel (A*), le destructeur ne sera pas appelé (et la mémoire de l'instance A ne sera pas libérée non plus) à moins que vous ne fassiez delete explicitement dans le destructeur de B. Si vous voulez une destruction automatique, regardez les pointeurs intelligents comme auto_ptr.

5
sharptooth

Vous devriez supprimer A vous-même dans le destructeur de B.

4
corné
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;
    }
};

Quand tu fais:

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

Le destructeur sera appelé uniquement si votre classe de base possède le mot-clé virtual.

Ensuite, si vous n'aviez pas de destructeur virtuel, seul ~ B () serait appelé. Mais puisque vous avez un destructeur virtuel, d'abord ~ ​​D () sera appelé, puis ~ B ().

Aucun membre de B ou D affecté sur le segment de mémoire ne sera désalloué à moins que vous ne les supprimiez explicitement. Et les supprimer appellera également leur destructeur.

2
Brian R. Bondy

Je me demandais pourquoi le destructeur de ma classe n'était pas appelé. La raison en était que j'avais oublié d'inclure la définition de cette classe (#include "class.h"). Je n'avais qu'une déclaration du type "classe A"; et le compilateur était heureux avec cela et m'a laissé appeler "delete".

1
Harri Luoma

Non, le pointeur sera supprimé. Vous devez appeler la suppression sur A explicite dans le destructeur de B.

0
RvdK

Le destructeur de l'objet de classe A ne sera appelé que si delete est appelé pour cet objet. Assurez-vous de supprimer ce pointeur dans le destructeur de classe B.

Pour un peu plus d'informations sur ce qui se passe lorsque delete est appelé sur un objet, voir: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9

0
Kris Kumler

non, il n'appellera pas destructeur pour la classe A, vous devriez l'appeler explicitement (comme PoweRoy l'a dit), supprimez la ligne 'delete ptr;' par exemple pour comparer ...

  #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;
  }
0
Darius Kucinskas

Vous avez quelque chose comme

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

Si vous appelez ensuite delete b;, rien ne se passe et a une fuite de mémoire. Essayer de se souvenir de delete b->a; n’est pas une bonne solution, mais il y en a quelques autres.

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

Ceci est un destructeur pour B qui supprimera a. (Si a est 0, cette suppression ne fait rien. Si a n'est pas 0 mais ne pointe pas vers la mémoire depuis le début, vous obtenez une corruption de tas.)

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

De cette façon, vous n'avez pas de pointeur, mais plutôt un auto_ptr <> (shared_ptr <>, ou d'autres pointeurs intelligents), et il est automatiquement supprimé lorsque b l'est.

L'une ou l'autre de ces méthodes fonctionne bien et j'ai utilisé les deux.

0
David Thornley