J’ai une classe (A) qui utilise une allocation de mémoire de tas 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 (B).
Quand j’aurai fini avec l’object B, j’appelle delete, ce que je suppose appelle le destructeur … Mais est-ce que cela appelle aussi le destructeur de la classe A?
D’après les réponses, je prends ça (merci de le modifier s’il est incorrect):
delete
instance des appels B B :: ~ B (); A::~A();
and A::~A
devrait explicitement delete
toutes les variables membres allouées au tas de A; Le destructeur de A fonctionnera lorsque sa durée de vie sera terminée. 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. S’il était alloué sur la stack, cela se produit automatiquement (c’est-à-dire quand il est hors de scope, voir RAII). S’il s’agit d’un membre d’une classe (et non d’un pointeur, mais d’un membre complet), cela se produit lorsque l’object 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 (ou même utilisable) où je ne l’ai pas utilisée.
auto_ptr
, unique_ptr
et shared_ptr
etc … sont parfaits pour rendre cette gestion de la vie beaucoup plus facile:
class A { shared_array someHeapMemory; public: A() : someHeapMemory(new char[1000]) {} ~A() { } // someHeapMemory is delete[]d automatically }; class B { shared_ptr APtr; public: B() : APtr(new A()) {} ~B() { } // APtr is deleted automatically }; int main() { shared_ptr BPtr = new B(); } // BPtr is deleted automatically
Lorsque vous appelez delete sur un pointeur alloué par new, le destructeur de l’object désigné sera appelé.
A * p = new A; delete p; // A:~A() called for you on obkect pointed to by p
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; }
Allouer une instance de B puis la supprimer est propre, car ce que B alloue en interne sera également supprimé dans le destructeur.
Mais les instances de la classe C vont perdre de la mémoire, car elles allouent une instance de A qui ne sera pas libérée (dans ce cas, C n’a même pas de destructeur).
Si vous avez un pointeur habituel ( A*
), le destructeur ne sera pas appelé (et la mémoire pour A
instance A
ne sera pas libérée) à moins que vous ne delete
explicitement le destructeur de B
Si vous voulez une destruction automatique, regardez les pointeurs intelligents comme auto_ptr
.
Vous devez supprimer A vous-même dans le destructeur de B.
class B { public: B() { p = new int[1024]; } virtual ~B() { cout<<"B destructor"<
Quand tu fais:
B *pD = new D(); delete pD;
Le destructeur sera appelé uniquement si votre classe de base a le mot-clé virtuel.
Alors, si vous n'aviez pas de destructeur virtuel, seul ~ B () serait appelé. Mais comme vous avez un destructeur virtuel, d'abord ~ D () sera appelé, puis ~ B ().
Aucun membre de B ou D alloué sur le tas ne sera désalloué à moins que vous ne le supprimiez explicitement. Et leur suppression appellera également leur destructeur.
Je me demandais pourquoi le destructeur de ma classe n’était pas appelé. La raison était que j’avais oublié d’inclure la définition de cette classe (#include “class.h”). Je n’avais qu’une déclaration comme “classe A”; et le compilateur était content et m’a laissé appeler “supprimer”.
Non, le pointeur sera supprimé. Vous devez appeler la suppression sur A explicite dans le destructeur de B.
Le destructeur pour l’object de classe A sera uniquement appelé si delete est appelé pour cet object. Assurez-vous de supprimer ce pointeur dans le destructeur de la classe B.
Pour un peu plus d’informations sur ce qui se passe lorsque la suppression est appelée sur un object, voir: http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.9
non, il n’appellera pas le destructeur pour la classe A, vous devez l’appeler explicitement (comme dit PoweRoy), supprimer la ligne ‘delete ptr;’ dans l’exemple pour comparer …
#include 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; }
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 à a, et vous avez une fuite de mémoire. Essayer de se rappeler de delete b->a;
n’est pas une bonne solution, mais il y en a plusieurs autres.
B::~B() {delete a;}
Ceci est un destructeur pour B qui supprimera un. (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 nouveau, vous obtenez une corruption de tas.)
auto_ptr a; ... b->a.reset(new A);
De cette façon, vous n’avez pas de pointeur, mais plutôt un auto_ptr <> (shared_ptr <> le fera aussi, ou d’autres pointeurs intelligents), et il est automatiquement supprimé lorsque b l’est.
Ces deux méthodes fonctionnent bien et j’ai utilisé les deux.