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

FAQ C++Consultez toutes les FAQ

Nombre d'auteurs : 34, nombre de questions : 368, derni�re mise � jour : 14 novembre 2021  Ajouter une question

 

Cette FAQ a �t� r�alis�e � partir des questions fr�quemment pos�es sur les forums de http://www.developpez.com et de l'exp�rience personnelle des auteurs.

Je tiens � souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne pr�tend pas non plus �tre compl�te. Si vous trouvez une erreur ou si vous souhaitez devenir r�dacteur, lisez ceci.

Sur ce, nous vous souhaitons une bonne lecture.

SommaireLes classes en C++Les destructeurs (12)
pr�c�dent sommaire suivant
 

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�:

Code c++ : S�lectionner tout
1
2
3
4
5
class MaClasse 
{ 
    // ...  
    ~MaClasse(); 
};

Mis � jour le 15 mai 2003 LFE

Le destructeur est appel� pour lib�rer les ressources acquises par un objet lorsque l'espace occup� par celui-ci doit �tre lib�r� :

Code c++ : S�lectionner tout
1
2
3
4
5
class CMyClass 
{ 
public: 
    ~CMyClass();// destructeur 
};
Si la classe ne contient pas de destructeur par d�faut, alors le compilateur en g�n�re un implicitement. Celui-ci va appeler les destructeurs des diff�rents membres puis celui des classes parents.
Si on doit utiliser la classe comme base dans un h�ritage pour une utilisation polymorphe (utilisation via une r�f�rence ou un pointeur sur la base), alors la classe de base doit d�finir un destructeur virtuel.

Mis � jour le 15 octobre 2009 3DArchi

Il est n�cessaire de rendre le destructeur d'une classe de base virtuel quand celle-ci est destin�e � �tre d�truite polymorphiquement. G�n�ralement d�s qu'un objet commence � �tre utilis� polymorphiquement (c'est-�-dire utilis� en place d'un objet de la classe m�re), il est fr�quent qu'il soit stock� et manipul� via un pointeur vers sa classe m�re, comme dans l'exemple suivant :

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream> 
  
// classe de base A destin�e � �tre d�riv�e 
class A 
{ 
public: 
    A() { std::cout << "Constructeur de A.\n"; } 
    ~A() { std::cout << "Destructeur de A.\n"; } 
  
    virtual void PrintName() { std::cout << "Classe A.\n"; } 
}; 
  
// B h�rite de A 
class B : public A 
{ 
public: 
    B() { std::cout << "Constructeur de B.\n"; } 
    ~B() { std::cout << "Destructeur de B.\n"; } 
  
    virtual void PrintName() { std::cout << "Classe B.\n"; } 
}; 
  
int main() 
{ 
    // utilisation polymorphe de B 
    A * a = new B; // construction de A et B 
    a->PrintName(); // affiche "Classe B" 
    delete a; // destruction de A mais pas de B ! 
}
Si vous avez compris comment fonctionne les fonctions membres virtuelles (voir Que signifie le mot-cl� virtual ?), vous pouvez alors deviner ce que l'instruction delete a; provoque : la destruction d'un objet de type A, donc l'appel de A::~A(), et de rien d'autre. Or, le type r�el de notre objet est B, et donc son destructeur n'est pas appel� ! Ceci produit un comportement ind�fini, qui se traduit souvent par des fuites de m�moires ou des probl�mes encore plus graves (tout d�pend de ce que le destructeur de B �tait cens� faire).
Le code pr�c�dent compil� avec Visual C++ 7.1 produit le r�sultat suivant :

Code : S�lectionner tout
1
2
3
4
Constructeur de A. 
Constructeur de B. 
Classe B. 
Destructeur de A.
Comme vous pouvez le constater, le destructeur de B n'est effectivement pas appel�. Ceci est r�solu en rendant le destructeur de A virtuel.

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
class A 
{ 
public: 
    A() { std::cout << "Constructeur de A.\n"; } 
    virtual ~A() { std::cout << "Destructeur de A.\n"; } 
  
    virtual void PrintName() { std::cout << "Classe A.\n"; } 
};
Dans un tel cas d'utilisation, il est donc important de ne pas oublier le destructeur virtuel dans la classe de base. Cela ne signifie pas pour autant qu'il faille rendre tous les destructeurs virtuels. Tout d'abord une fonction membre virtuelle engendre un surco�t lors de son appel ainsi qu'en termes de d'occupation m�moire. Mais aussi un destructeur virtuel indique que la classe a �t� r�alis�e dans le but d'�tre d�riv�e.
Rendre un destructeur virtuel ou non ne se limite donc pas � l'ajout du mot-cl� virtual mais doit �tre l'aboutissement d'une r�flexion men�e sur l'utilisation de la classe. Une classe qui n'est pas destin�e � �tre d�riv�e n'a pas � avoir de destructeur virtuel.

Mis � jour le 22 novembre 2004 Aurelien.Regat-Barrel

Oui, il est possible d'appeler explicitement le destructeur d'une classe, bien que ce soit une pratique � proscrire. La raison en est simple : il est appel� automatiquement par le compilateur lorsque l'objet va �tre d�truit, et ce, que vous l'ayez appel� ou non. Autrement dit, dans le code suivant :

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream> 
  
class Test 
{ 
public: 
    ~Test() { std::cout << "Destruction\n"; } 
}; 
  
int main() 
{ 
    Test t; 
    t.~Test(); // appel explicite du destructeur 
} // ici, le compilateur appelle � nouveau le destructeur
Le destructeur est appel� deux fois. En fonction de ce qu'il fait, cela peut avoir des cons�quences dramatiques. Mais surtout cela ne sert � rien puisque c'est le travail du compilateur.
L'un des seuls cas o� l'on doit appeler le destructeur explicitement est lorsqu'on a utilis� l'op�rateur new de placement pour cr�er le m�me objet. Dans ce cas, de m�me qu'on s'est substitu� au compilateur pour g�rer la vie de l'objet, il faut faire le travail jusqu'au bout et g�rer sa destruction. Voir � ce sujet Qu'est-ce que � placement new � et dans quels cas l'utilise-t-on ?. Il y a aussi des fois o� l'on est oblig� de le faire, comme quand on d�veloppe avec un ancien compilateur qui faillit � son devoir et n'appelle pas le destructeur sur les objets statiques. Dans ce cas aussi l'appel explicite au destructeur est justifi�.

Mis � jour le 22 novembre 2004 Aurelien.Regat-Barrel Laurent Gomila LFE

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 :

Code c++ : S�lectionner tout
1
2
3
4
5
6
void userCode() 
{ 
    Fred a; 
    Fred b; 
    // ... 
}

Mis � jour le 19 mars 2004 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] :

Code c++ : S�lectionner tout
1
2
3
4
5
void userCode() 
{ 
    Fred a[10]; 
    // ... 
}

Mis � jour le 19 mars 2004 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.

Mis � jour le 19 mars 2004 Cline

Il suffit de limiter la dur�e de vie de l'objet local en le pla�ant dans un bloc { ... } artificiel :

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
void someCode() 
{ 
    { 
        File f; 
        // ... [Ici, le fichier est encore ouvert] ... 
    } 
    //  Ici, le destructeur de f est appel� automatiquement ! 
  
    // ... [Le code ici s'ex�cutera apr�s que f soit ferm�]  ... 
}

Mis � jour le 19 mars 2004 Cline

Dans la plupart des cas, il est possible de limiter la dur�e de vie d'un objet local en le pla�ant dans un 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 fonction membre close(). Le destructeur se contenterait simplement d'appeler cette fonction. Notez que la fonction 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 fonction que fileHandle_ n'est pas �gale � cette valeur :

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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�mes qui conviennent pour fermer le fichier] ... 
        fileHandle_ = -1; 
      } 
}
Notez que les autres fonctions membres 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�).

Mis � jour le 19 mars 2004 Cline

Dans la plupart des cas, NON.

� moins que vous ayez utilis� placement new, utilisez delete plut�t que d'appeler explicitement le destructeur de l'objet. Imaginez par exemple que vous ayez allou� un objet gr�ce � une � new expression � classique :

Code c++ : S�lectionner tout
Fred* p = new Fred();
Le destructeur Fred::~Fred() va �tre appel� automatiquement quand vous utiliserez delete.

Code c++ : S�lectionner tout
delete p; // p->~Fred() est appel� automatiquement
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.

Mis � jour le 19 mars 2004 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.

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Member { 
    public: 
      ~Member(); 
       // ... 
}; 
  
class Fred { 
    public: 
      ~Fred(); 
       // ... 
    private: 
      Member x_; 
      Member y_; 
      Member z_; 
}; 
  
Fred::~Fred() 
{ 
    // Le compilateur appelle automatiquement  z_.~Member() 
    // Le compilateur appelle automatiquement  y_.~Member() 
    // Le compilateur appelle automatiquement  x_.~Member() 
}

Mis � jour le 19 mars 2004 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 base sont d�truites apr�s les objets membres. Et dans le cas d'un h�ritage multiple, les classes de base directes sont d�truites dans l'ordre inverse de celui dans lequel elles apparaissent dans la d�claration d'h�ritage.

Code c++ : S�lectionner tout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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 automatiquement x_.~Member() 
    // Le compilateur appelle automatiquement 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.

Mis � jour le 19 mars 2004 Cline

Proposer une nouvelle r�ponse sur la FAQ

Ce n'est pas l'endroit pour poser des questions, allez plut�t sur le forum de la rubrique pour �a


R�ponse � la question

Liens sous la question
pr�c�dent sommaire suivant
 

Les sources pr�sent�es sur cette page sont libres de droits et vous pouvez les utiliser � votre convenance. Par contre, la page de pr�sentation constitue une �uvre intellectuelle prot�g�e par les droits d'auteur. Copyright � 2025 Developpez Developpez LLC. Tous droits r�serv�s Developpez LLC. Aucune reproduction, m�me partielle, ne peut �tre faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'� trois ans de prison et jusqu'� 300 000 � de dommages et int�r�ts.