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?
À partir des réponses, je prends cela (éditez s'il vous plaît si incorrect):
delete
d'une instance de B appelle B :: ~ B ();A::~A();
A::~A
devrait explicitement delete
toutes les variables de membre allouées par tas de l'objet A;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
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
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).
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
.
Vous devriez supprimer A vous-même dans le destructeur de 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;
}
};
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.
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".
Non, le pointeur sera supprimé. Vous devez appeler la suppression sur A explicite dans le destructeur de B.
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
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;
}
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.