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éeLes 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.
Défi
FacileConstruisons 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 classeConnectionqui 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
- Un attribut privé
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
Connectionsur 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"
- Créez une portée en utilisant des accolades
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éeLes 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;
}
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