Analyse approfondie du destructeur
Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 24 sur 104.
Un destructeur est une fonction membre spéciale qui s'exécute automatiquement lorsqu'un objet est détruit. Son rôle principal est de libérer les ressources acquises par l'objet au cours de sa durée de vie, telles que la mémoire allouée dynamiquement, les descripteurs de fichiers ou les connexions réseau.
Le destructeur a le même nom que la classe, précédé d'un tilde ~. Il ne prend aucun paramètre et n'a pas de type de retour :
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Les destructeurs sont appelés automatiquement dans les situations suivantes :
- Les objets de la pile sortent de la portée
deleteest appelé sur un objet alloué sur le tas- La durée de vie d'un objet temporaire se termine
void example() {
FileHandler f1("data.txt", 100); // Constructeur appelé
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Destructeur appelé pour f2
} // Destructeur appelé pour f1 (sort de la portée)Contrairement aux constructeurs, une classe ne peut avoir qu'un seul destructeur. Vous ne pouvez pas le surcharger.
Si vous n'en définissez pas un, le compilateur génère un destructeur par défaut qui ne fait rien de particulier - il détruit simplement chaque membre. Pour les classes gérant des ressources, vous devez écrire le vôtre pour éviter les fuites de mémoire.
Défi
FacileConstruisons un gestionnaire de session qui suit les sessions utilisateur actives et démontre comment les destructeurs nettoient automatiquement les ressources lorsque les objets sont détruits — qu'ils sortent de la portée (scope) ou qu'ils soient explicitement supprimés.
Vous allez créer deux fichiers pour organiser votre code :
Session.h: Définissez une classeSessionqui représente une session utilisateur active avec des données allouées dynamiquement. Votre classe doit avoir :- Des membres privés : un
username(string), unsessionId(int), et un pointeur vers un tableau d'entiers appeléactivityLogqui suit les actions de l'utilisateur, ainsi qu'unlogSizepour la taille du tableau. - Un constructeur qui prend un nom d'utilisateur, un ID de session et une taille de journal. Il doit allouer le tableau du journal d'activité sur le tas (heap), initialiser tous les éléments à 0, et afficher
"Session <sessionId> started for <username>" - Un destructeur qui libère la mémoire allouée et affiche
"Session <sessionId> ended for <username>" - Une méthode
logActivity(int activityCode)qui stocke le code d'activité dans le prochain emplacement disponible (suivez la position actuelle en interne). - Une méthode
getActivityCount()qui retourne le nombre d'activités enregistrées. - Une méthode
getUsername()qui retourne le nom d'utilisateur.
- Des membres privés : un
main.cpp: Démontrez le comportement du destructeur dans différents scénarios. Lisez un nom d'utilisateur et une taille de journal depuis l'entrée (chacun sur une ligne séparée), puis :- Créez un bloc de portée en utilisant des accolades
{ }et, à l'intérieur, créez uneSessionallouée sur la pile (stack) avec le nom d'utilisateur saisi, l'ID de session101, et la taille de journal saisie. Enregistrez deux activités avec les codes1et2, puis affichez"Stack session activities: <count>". Lorsque le bloc se termine, le destructeur doit s'exécuter automatiquement. - Après le bloc, affichez
"Stack session destroyed" - Créez une
Sessionallouée sur le tas (heap) en utilisantnewavec le nom d'utilisateur"Guest", l'ID de session202, et une taille de journal de3. Enregistrez une activité avec le code5, affichez"Heap session activities: <count>", puis supprimez-la explicitement avecdelete. - Après la suppression, affichez
"Heap session destroyed"
- Créez un bloc de portée en utilisant des accolades
Ce défi montre les deux principales façons dont les destructeurs sont appelés : automatiquement lorsque les objets de la pile quittent la portée, et manuellement lorsque vous supprimez des objets du tas. Les deux chemins doivent libérer correctement le journal d'activité alloué dynamiquement pour éviter les fuites de mémoire.
Incluez votre fichier d'en-tête dans main.cpp en utilisant #include "Session.h".
Aide-mémoire
Un destructeur est une fonction membre spéciale qui s'exécute automatiquement lorsqu'un objet est détruit. Il libère des ressources telles que la mémoire allouée dynamiquement, les descripteurs de fichiers ou les connexions réseau.
Le destructeur porte le même nom que la classe, précédé d'un tilde ~. Il ne prend aucun paramètre et n'a pas de type de retour :
class FileHandler {
std::string filename;
int* buffer;
public:
FileHandler(std::string name, size_t size)
: filename(name), buffer(new int[size]) {
std::cout << "Opening " << filename << "\n";
}
~FileHandler() {
delete[] buffer;
std::cout << "Closing " << filename << "\n";
}
};Les destructeurs sont appelés automatiquement lorsque :
- Les objets de la pile sortent de la portée
deleteest appelé sur un objet alloué sur le tas- La durée de vie d'un objet temporaire se termine
void example() {
FileHandler f1("data.txt", 100); // Constructeur appelé
FileHandler* f2 = new FileHandler("log.txt", 50);
delete f2; // Destructeur appelé pour f2
} // Destructeur appelé pour f1 (sort de la portée)Une classe ne peut avoir qu'un seul destructeur (pas de surcharge). Si vous n'en définissez pas, le compilateur génère un destructeur par défaut. Pour les classes gérant des ressources, vous devez écrire le vôtre pour éviter les fuites de mémoire.
Essayez vous-même
#include <iostream>
#include <string>
#include "Session.h"
using namespace std;
int main() {
// Lire l'entrée
string username;
int logSize;
getline(cin, username);
cin >> logSize;
// TODO: Créer un bloc de portée avec des accolades { }
// À l'intérieur du bloc :
// - Créer une Session allouée sur la pile avec le username d'entrée, l'ID de session 101, et la taille de log d'entrée
// - Enregistrer deux activités avec les codes 1 et 2
// - Afficher "Stack session activities: <count>"
// Lorsque le bloc se termine, le destructeur s'exécute automatiquement
// TODO: Après le bloc, afficher "Stack session destroyed"
// TODO: Créer une Session allouée sur le tas en utilisant new
// - Username: "Guest", ID de session : 202, taille de log : 3
// - Enregistrer une activité avec le code 5
// - Afficher "Heap session activities: <count>"
// - Supprimer la session avec delete
// TODO: Après la suppression, afficher "Heap session destroyed"
return 0;
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation Orientée Objet
1Fondamentaux de la POO
Fichiers externesBuild et Compilation C++Fichiers d'en-tête et Fichiers sourceEspaces de noms et PortéeIntroduction à la POO en C++Classes vs ObjetsLe pointeur 'this'Méthodes (Fonctions membres)Attributs (Membres de données)Bases des Ctors et DtorsRécapitulatif - Calculatrice simple4Propriétés de classe
Membres d'instance vs membres statiquesGetters et SettersFonctions membres constMot-clé mutableMéthodes et variables statiquesFonctions et classes amiesRécapitulatif - Gestionnaire de compte bancaire7Héritage
Héritage de baseNiveaux d'accès à l'héritageOrdre d'appel des Ctor et DtorRedéfinition de méthodesFonctions virtuelles et VTableHéritage multipleHéritage virtuelRécapitulatif - Hiérarchie des employés10Présentation de la STL
Présentation et philosophie de la STLConteneurs de la STLItérateursAlgorithmes de la STLFoncteurs et expressions lambdaRécapitulatif - Fréquence des mots13Patrons de conception, Partie 1
Introduction aux patrons de conceptionPatron SingletonFabrique & Fabrique abstraitePatron MonteurPatron ObservateurPatron Stratégie2Gestion de la mémoire
Mémoire Pile vs TasPointeurs et RéférencesMémoire dynamique (new/delete)Smart Pointers en C++RAII en C++Récapitulatif - Gestionnaire de tableaux dynamiques5Encapsulation
Spécificateurs d'accès en C++Spécificateurs d'accès en profondeurMasquage d'informationStruct vs ClassClasses imbriquées et internesRécapitulatif - Système de gestion d'étudiants8Polymorphisme
Polymorphisme : Compilation vs ExécutionSurcharge de fonctionsRetour sur les fonctions virtuellesFonctions virtuelles puresClasses abstraitesConception d'interfaces en C++Dynamic Casting & RTTIRécapitulatif - Calculateur de formes11Concepts avancés de la POO
Composition vs HéritageMixins via CRTPIdiome PimplEffacement de typeEnum Classes & Typage fortGestion des exceptions en POOHiérarchies d'exceptions personnalisées14Patrons de conception, Partie 2
Patron CommandePatron AdaptateurPatron DécorateurPatron Template MethodPatron ÉtatPatron CompositeRAII en tant que patron3Constructeurs et Destructeurs
Constructeur par défautConstructeur paramétréConstructeur de copieConstructeur de déplacementListes d'initialisation du constructeurConstructeurs déléguésAnalyse approfondie du destructeurRègle de trois / cinq / zéroRécapitulatif - Classe String6Surcharge d'opérateurs
Introduction à la surcharge d'opérateursSurcharge des opérateurs arithmétiquesSurcharge des opérateurs de comparaisonOpérateurs de fluxSurcharge de l'opérateur d'affectationSurcharge des opérateurs [] et ()Opérateurs de conversion de typeRécapitulatif - Classe Matrix9Templates
Templates de fonctionsTemplates de classesSpécialisation de templatesTemplates variadiquesBases de SFINAE & Type TraitsRécapitulatif - Conteneur générique