Le destructeur est contient le code qui est appelé pour effectuer une ou plusieurs opérations avant que l'objet soit supprimé de la mémoire.
Le destructeur est une fonction qui a pour nom ~ClassName
où ClassName
est le nom de la classe. L'opérateur ~
correspond à l'opérteur négation qui peut être donc vu comme l'opération de destruction, qui est la négation de l'opération de construction, d'où la syntaxe du destructeur.
class CString { private: const char* m_string; public: CString(const char* aString): m_string(strdup(aString) {} CString(const CString& aString): m_string(strdup(aString.m_string) {} ~CString() { free(m_string); } };
Le destructeur ~CString()
est appelé juste avant la destruction de la classe et il procède à la libération de la mémoire qui a été allouée par l'appel à la fonction strdup
au moment de la création de l'objet.
Un destructeur n'est a priori responsable que de la suppression des ressources allouées par la classe actuelle et non pas des ressources allouées par une classe dont il dérive
Il est possible d'appeler un destructeur de manière explicite, cependant, ceci est normalement à déconseiller puisque le destructeur risque de procéder à la libération d'une ressource déjà libérée et donc de générer une faute d'exécution.
int main() { CString str("abc"); str.~CString() // Appel le destructeur return 0; // retourne une faute d'accès à la mémoire. }
Cependant, dans certains cas, il est possible de concevoir un destructeur qui puisse être appelé plusieurs fois de suite. Si nous modifions le code du destructeur de ~CString
comme suit,
~CString() { if(m_string != NULL) { free(m_string); m_string = NULL; } }
le deuxième appel au destructeur ne générera pas d'erreurs. Ce type d'approche peut se justifier lorsque nous souhaitons détruire l'objet 1) avant que la destruction de l'objet soit véritablement envisagé par le compilateur.