Menu
CoddyTech

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 destructeur par défaut qui ne fait rien de particulier : il détruit simplement chaque membre. Pour les classes qui gèrent des ressources, vous devez écrire le vôtre 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 sont 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 :
    • Des 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 pour la taille du tableau
    • Un constructeur qui accepte 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 ses é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) ; si le journal est déjà plein, l'appel est ignoré, afin que le nombre ne dépasse jamais la taille du journal
    • 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 créez à l'intérieur une Session allouée sur la pile avec le nom d'utilisateur fourni, l'identifiant de session 101 et la taille de journal fournie. 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 une Session allouée 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 supprimez-la explicitement avec 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 de la pile sortent de leur portée, et manuellement lorsque vous supprimez des objets du tas. Les deux chemins doivent libérer correctement le journal d'activités alloué dynamiquement afin d'éviter les fuites 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 log en entrée
    //   - Logger 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 log : 3
    //   - Logger 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