Menu
Coddy logo textTech

Approfondissement des destructeurs

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 que l’objet a acquises 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 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 dans les situations suivantes :

  • Les objets de la pile sortent de leur portée
  • delete est appelé sur un objet alloué sur le tas
  • La durée de vie d’un objet temporaire prend fin
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 destructor par défaut qui ne fait rien de spécial : il détruit simplement chaque membre. Pour les classes qui gèrent des ressources, vous devez écrire votre propre destructor afin d’éviter les fuites de mémoire.

challenge icon

Défi

Facile

Construisons un gestionnaire de sessions qui suit les sessions utilisateur actives et montre comment les destructeurs nettoient automatiquement les ressources lorsque les objets sont détruits, qu’ils sortent de leur portée ou qu’ils soient explicitement supprimés.

Vous allez créer deux fichiers pour organiser votre code :

  • Session.h : définissez une classe Session qui représente une session utilisateur active avec des données allouées dynamiquement. Votre classe doit comporter :
    • Membres privés : un username (chaîne de caractères), un sessionId (entier) et un pointeur vers un tableau d’entiers appelé activityLog qui suit les actions de l’utilisateur, ainsi qu’un logSize indiquant la taille du tableau
    • Un constructeur qui reçoit un nom d’utilisateur, un identifiant de session et une taille de journal. Il doit allouer le tableau du journal d’activités sur le tas, 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 l’emplacement disponible suivant (suivez la position actuelle en interne)
    • Une méthode getActivityCount() qui renvoie le nombre d’activités enregistrées
    • Une méthode getUsername() qui renvoie le nom d’utilisateur
  • main.cpp : démontrez le comportement des destructeurs dans différents scénarios. Lisez un nom d’utilisateur et une taille de journal depuis l’entrée (chacun sur une ligne distincte), puis :
    • Créez un bloc de portée à l’aide d’accolades { } et, à l’intérieur, créez un Session alloué sur la pile avec le nom d’utilisateur saisi, l’identifiant de session 101 et la taille de journal saisie. Enregistrez deux activités avec les codes 1 et 2, 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 un Session alloué sur le tas à l’aide de new, avec le nom d’utilisateur "Guest", l’identifiant de session 202 et une taille de journal de 3. Enregistrez une activité avec le code 5, affichez "Heap session activities: <count>", puis utilisez explicitement delete.
    • Après la suppression, affichez "Heap session destroyed"

Ce défi montre les deux principales façons dont les destructeurs sont appelés : automatiquement lorsque les objets sur la pile sortent de leur portée, et manuellement lorsque vous supprimez des objets du tas. Dans les deux cas, le journal d’activités alloué dynamiquement doit être correctement libéré afin d’éviter les fuites de mémoire.

Incluez votre fichier d’en-tête dans main.cpp à l’aide de #include "Session.h".

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 nom d'utilisateur en entrée, l'ID de session 101 et la taille de journal en entrée
    //   - Enregistrer deux activités avec les codes 1 et 2
    //   - Print "Stack session activities: <count>"
    // Lorsque le bloc se termine, le destructeur s'exécute automatiquement
    
    // TODO: After the block, print "Stack session destroyed"
    
    // TODO: Créer une Session allouée sur le tas en utilisant new
    //   - Nom d'utilisateur : "Guest", ID de session : 202, taille de journal : 3
    //   - Enregistrer une activité avec le code 5
    //   - Print "Heap session activities: <count>"
    //   - Supprimer la session
    
    // TODO: After deletion, print "Heap session destroyed"
    
    return 0;
}
quiz iconTestez-vous

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

Entraînez-vous par vous-même : Compilateur C++ en ligne