Le Raii

Dans tout programme, on utilise des ressouces qui doivent être libérées explicitement ; on alloue de la mémoire, qu’il faudra libérer, on ouvre un fichier, qu’il faudra refermer, on verrouille un mutex, qu’il faudra déverrouiller, on charge une dll, qu’il faudra décharger… Mais il est délicat de prévoir tous les scénarios de sortie et de libérer la ressource dans tous les cas, notamment en cas d’exception.

Une solution à ce problème est le raii, sigle anglais de « Resource Acquisition Is Initialization. » Cela consiste à encapsuler la ressource dans une classe, dont le constructeur acquiert la ressource, et le destructeur la libère.

Un double exemple :

class CriticalSection { public: CriticalSection() { ::InitializeCriticalSection(&Section_); } ~CriticalSection() { ::DeleteCriticalSection(&Section_); } class Lock { public: Lock(CriticalSection& cs) : Section_(cs) { Section_.Enter(); } ~Lock() { Section_.Leave(); } private: CriticalSection& Section_; }; private: ::CRITICAL_SECTION Section_; void Enter() { ::EnterCriticalSection(&Section_); } void Leave() { ::LeaveCriticalSection(&Section_); } };

Il suffit alors d’instancier un objet pour allouer la ressource… et de le laisser sortir de portée pour la libérer.

{ CriticalSection csFile; { CriticalSection::Lock lock(csFile); WorkOnFiles(); } // ici, csFile est relāchée } // ici, csFile est détruite.

Si une exception se produit dans WorkOnFiles(), la section critique sera bien libérée et bien détruite quand même.

La bibliothèque standard fournit std::vector pour remplacer les tampons gérés avec malloc()/free(), et std::ifstream/std::ofstream pour les fichiers ; si vous les avez utilisés, vous avez fait du raii sans le savoir !