IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)



Qu'est-ce qu'un destructeur ?
auteur : LFE
Un destructeur est ce qui détruit un objet, libère la mémoire allouée dans le constructeur ou ce qui n'a pas été libéré durant la vie de l'objet.
Il porte le même nom que la classe précédé du signe ~.
Un destructeur ne prend aucun paramètre et ne renvoie aucune valeur de retour. Sa déclaration se fait de la façon suivante :

class MaClasse { // ... ~MaClasse(); };
lien : Qu'est-ce qu'un constructeur ?

Puis-je surcharger un destructeur ?
auteur : LFE
Non, cela n'a aucun sens. Le destructeur est appelé automatiquement à la fin de vie de l'objet. Il ne peut pas être appelé explicitement.


Est-il possible d'invoquer explicitement le destructeur d'une classe ?
auteur : LFE
Oui, il est tout à fait possible d'appeler explicitement le destructeur d'une classe, bien que, à mon avis, ce soit une pratique à proscrire. S'il est nécessaire, pour une raison ou une autre, de devoir effectuer une libération anticipée des ressources de la classe, il est beaucoup plus simple et lisible de créer une fonction qui se chargera de libérer ces ressources, sans pour autant détruire celle-ci.
Ceci peut être utilisé par des classes devant allouer de grandes quantités de mémoire et ayant une durée d'utilisation très brève.


Dans quel ordre les objets locaux sont-ils détruits?
auteur : Marshall Cline
Dans l'ordre inverse de celui dans lequel ils ont été construits : le premier objet construit est le dernier détruit.

Dans l'exemple ci-dessous, le destructeur de b sera exécuté en premier, suivi du destructeur de a:

void userCode() { Fred a; Fred b; // ... }

Dans quel ordre les objets contenus dans un tableau sont-ils détruits?
auteur : Marshall Cline
Dans l'ordre inverse de celui dans lequel ils ont été construits: le premier objet construit est le dernier détruit.

Dans l'exemple ci-dessous, l'ordre des destructions est a[9], a[8], ..., a[1], a[0] :

void userCode() { Fred a[10]; // ... }

Doit-on détruire explicitement les objets locaux ?
auteur : Marshall Cline
Surtout pas!

Car le destructeur sera appelé une deuxième fois au niveau de l'accolade fermant le bloc dans lequel l'objet a été créé. La norme C++ le garantit et vous ne pouvez rien faire pour empêcher que ça arrive; c'est automatique. Et ça risque de vraiment très mal se passer si le destructeur d'un objet est appelé deux fois de suite.


Et si on veut absolument qu'un objet local "meure" avant l'accolade fermant le bloc dans lequel il a été créé?
auteur : Marshall Cline
Il suffit de limiter la durée de vie de l'objet local en le placant dans un bloc { ... } artificiel:

void someCode() { { File f; // ... [Ici, le fichier est encore ouvert] ... } // ^— Ici, le destructeur de f est appelé automagiquement! // ... [Le code ici s'executera après que f soit fermé] ... }

Et s'il n'est pas possible de placer l'objet local dans une bloc artificiel?
auteur : Marshall Cline
Dans la plupart des cas, il est possible de limiter la durée de vie d'un objet local en le placant dans une bloc artificiel ({ ... }) . Si, pour une raison ou pour une autre, ce n'est pas possible, ajoutez à la classe une fonction membre qui a le même effet que le destructeur. Mais n'appelez pas le destructeur vous-même!

Dans le cas de File, par exemple, vous pourriez ajouter à la classe une méthode close(). Le destructeur se contenterait simplement d'appeler cette méthode. Notez que la méthode close() aura besoin de marquer l'objet File de façon à ne pas tenter de fermer le fichier s'il l'est déjà, ce qui peut se produire si close() est appelée plusieurs fois. L'une des solutions possibles est de donner à la donnée membre fileHandle_ une valeur qui n'a pas de sens, par exemple -1, et de vérifier à l'entrée de la méthode que fileHandle_ n'est pas égale à cette valeur :

class File { public: void close(); ~File(); // ... private: int fileHandle_; // fileHandle_ >= 0 seulement si le fichier est ouvert }; File::~File() { close(); } void File::close() { if (fileHandle_ >= 0) { // ... [Utiliser les appels système qui conviennent pour fermer le fichier] ... fileHandle_ = -1; } }
Notez que les autres méthodes de la classe File peuvent elles aussi avoir besoin de vérifier que fileHandle_ n'est pas égale à -1 (c'est-à-dire, de vérifier que le fichier n'est pas fermé).


Peut-on détruire explicitement un objet alloué par new ?
auteur : Marshall Cline
Dans la plupart des cas, NON.

À moins que vous ayiez utilisé placement new , utilisez delete plutôt que d'appeler explicitement le destructeur de l'objet. Imaginez par exemple que vous ayiez alloué un objet grâce à une "new expression" classique :

Fred* p = new Fred();
Le destructeur Fred::~Fred() va être appelé automagiquement quand vous utiliserez delete

delete p; // p->~Fred() est appelé automagiquement
N'appelez pas explicitement le destructeur, car cela ne libèrera pas la mémoire allouée pour l'objet Fred lui-même. Gardez à l'esprit que delete p a deux effets : il appelle le destructeur et il désalloue la mémoire.


Dans le code d'un destructeur, doit-on détruire explicitement les objets membres?
auteur : Marshall Cline
Non. Il n'est jamais nécessaire d'appeler explicitement un destructeur (sauf si l'objet a été créé avec un placement new ).

Le destructeur d'une classe (il existe même si vous ne l'avez pas défini) appelle automatiquement les destructeurs des objets membres. Ces objets sont détruits dans l'ordre inverse de celui dans lequel ils apparaissent dans la déclaration de la classe.

class Member { public: ~Member(); // ... }; class Fred { public: ~Fred(); // ... private: Member x_; Member y_; Member z_; }; Fred::~Fred() { // Le compilateur appelle automagiquement z_.~Member() // Le compilateur appelle automagiquement y_.~Member() // Le compilateur appelle automagiquement x_.~Member() }

Dans le code du destructeur d'une classe dérivée, doit-on appeler explicitement le destructeur de la classe de base ?
auteur : Marshall Cline
Non. Il n'est jamais nécessaire d'appeler explicitement un destructeur ( sauf si l'objet a été créé avec un placement new ).

Le destructeur d'une classe dérivée (il existe même si vous ne l'avez pas défini) appelle automatiquement les destructeurs des sous-objets des classes de base. Les classes de bases sont détruites après les objets membres. Et dans le cas d'un héritage multiple, l es classes de bases directes sont détruites dans l'ordre inverse de celui dans lequel elles apparaissent dans la déclaration d'héritage.

class Member { public: ~Member(); // ... }; class Base { public: virtual ~Base(); // Un destructeur virtuel // ... }; class Derived : public Base { public: ~Derived(); // ... private: Member x_; }; Derived::~Derived() { // Le compilateur appelle automagiquement x_.~Member() // Le compilateur appelle automagiquement calls Base::~Base() }
Note: l'ordre des destructions dans le cas d'un héritage virtuel est plus compliqué. Si vous voulez vous baser sur l'ordre des destructions dans le cas d'un héritage virtuel, il va vous falloir plus d'informations que celles simplement contenues dans cette FAQ.



Ce document issu de http://www.developpez.com est soumis à la licence GNU FDL traduit en français ici.
Permission vous est donnée de distribuer, modifier des copies de cette page tant que cette note apparaît clairement.
Certaines parties de ce document sont sous copyright Marshall Cline