Menu
Coddy logo textTech

RAII en C++

Fait partie de la section Programmation Orientée Objet du Journey C++ de Coddy — leçon 16 sur 104.

RAII (Resource Acquisition Is Initialization) est un idiome C++ fondamental où la gestion des ressources est liée à la durée de vie de l'objet. L'idée est simple : acquérir les ressources dans le constructeur, les libérer dans le destructeur.

Lorsqu'un objet est créé, il acquiert toutes les ressources dont il a besoin. Lorsque l'objet sort de la portée, son destructeur libère automatiquement ces ressources. Cela garantit le nettoyage même si des exceptions surviennent.

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // Acquérir la ressource
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // Libérer la ressource
    }
};

Avec RAII, vous n'oubliez jamais de nettoyer :

void processFile() {
    FileHandler handler("data.txt");  // Ressource acquise
    // Travailler avec le fichier...
    // Si une exception est levée ici, le destructeur s'exécute toujours !
}   // Ressource automatiquement libérée

Les pointeurs intelligents sont l'exemple parfait du RAII en action. Un unique_ptr acquiert la propriété de la mémoire du tas dans son constructeur et la supprime dans son destructeur. Vous avez déjà utilisé le RAII sans vous en rendre compte !

Le RAII s'applique à n'importe quelle ressource : mémoire, descripteurs de fichiers, connexions réseau, mutex ou connexions de base de données. En enveloppant les ressources dans des objets, le C++ garantit un nettoyage déterministe et élimine des catégories entières de bogues tels que les fuites et les descripteurs suspendus.

challenge icon

Défi

Facile

Construisons un gestionnaire de connexion qui démontre le RAII en gérant automatiquement le cycle de vie de connexions de type réseau. Lorsqu'une connexion est créée, elle doit s'ouvrir ("open"), et lorsqu'elle sort de la portée (scope), elle doit se fermer automatiquement ("close") — aucun nettoyage manuel n'est requis !

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

  • Connection.h : Définissez une classe Connection qui gère une ressource de connexion en utilisant les principes du RAII. La classe doit avoir :
    • Un attribut privé connectionId (string) pour identifier la connexion
    • Un attribut privé isOpen (bool) pour suivre l'état de la connexion
    • Un constructeur qui prend un ID de connexion, définit isOpen à true, et affiche "Opening connection: <id>"
    • Un destructeur qui vérifie si la connexion est ouverte, la ferme en définissant isOpen à false, et affiche "Closing connection: <id>"
    • Une méthode send(string message) qui affiche "[<id>] Sending: <message>" si la connexion est ouverte
    • Une méthode getId() qui retourne l'ID de la connexion
  • main.cpp : Démontrez comment le RAII assure un nettoyage automatique en lisant un ID de connexion et un message depuis l'entrée. Ensuite :
    • Créez une portée en utilisant des accolades { }
    • À l'intérieur de cette portée, créez un objet Connection sur la pile (stack) avec l'ID saisi
    • Utilisez la connexion pour envoyer le message saisi
    • Laissez la portée se terminer (la connexion doit se fermer automatiquement)
    • Après la portée, affichez "Connection out of scope"

La beauté du RAII est que vous n'avez pas besoin de vous rappeler de fermer la connexion — le destructeur s'en occupe automatiquement lorsque l'objet quitte la portée. Ce modèle empêche les fuites de ressources même si quelque chose d'inattendu se produit dans votre code.

Incluez votre fichier d'en-tête dans main.cpp en utilisant #include "Connection.h".

Aide-mémoire

Le RAII (Resource Acquisition Is Initialization) est un idiome C++ où la gestion des ressources est liée à la durée de vie de l'objet. Les ressources sont acquises dans le constructeur et libérées dans le destructeur.

Lorsqu'un objet sort de la portée, son destructeur libère automatiquement les ressources, garantissant le nettoyage même si des exceptions surviennent :

class FileHandler {
    std::FILE* file;
public:
    FileHandler(const char* filename) {
        file = std::fopen(filename, "r");  // Acquérir la ressource
    }
    
    ~FileHandler() {
        if (file) std::fclose(file);       // Libérer la ressource
    }
};

Le RAII garantit un nettoyage automatique :

void processFile() {
    FileHandler handler("data.txt");  // Ressource acquise
    // Travailler avec le fichier...
    // Si une exception est levée, le destructeur s'exécute toujours !
}   // Ressource automatiquement libérée

Les pointeurs intelligents comme unique_ptr sont des exemples de RAII. Ils acquièrent de la mémoire sur le tas dans le constructeur et la suppriment dans le destructeur.

Le RAII s'applique à n'importe quelle ressource : mémoire, descripteurs de fichiers, connexions réseau, mutex ou connexions à des bases de données. Il assure un nettoyage déterministe et élimine les bogues tels que les fuites et les handles suspendus (dangling handles).

Essayez vous-même

#include <iostream>
#include <string>
#include "Connection.h"

using namespace std;

int main() {
    string connectionId;
    string message;
    
    // Lire l'entrée
    cin >> connectionId;
    cin.ignore();
    getline(cin, message);

    // TODO: Créer une portée (scope) en utilisant des accolades { }
    // À l'intérieur de la portée :
    //   - Créer un objet Connection sur la pile (stack) avec connectionId
    //   - Utiliser la connexion pour envoyer le message
    // Laisser la portée se terminer (le destructeur sera appelé automatiquement)

    // TODO: Une fois la portée terminée, afficher "Connection out of scope"

    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