Skip to content

Acquisition de ressources par initialisation

L'ouvrage de référence du C++, dans lequel la méthode est exposée

"L'acquisition de ressources par initialisation" est aussi appelée "L'acquisition de ressource, c'est l'initialisation", traduction directe de l'anglais "ressource acquisition is initialization" (RAII).


Il s'agit d'une technique de programmation qui permet une gestion automatique des ressources informatiques (mémoire, fichiers, locks, connexion à une API, ...). Elle permet en effet d'assurer la libération immédiate des ressources lorsque celles-ci ne sont plus utiles, que ce soit dans le cadre d'un fonctionnement normal ou bien de conditions exceptionnelles (erreurs).


Cette technique est apparue à la suite de discussions sur l'évolution du langage C++ (début des années 90 si ma mémoire ne me fait pas défaut). Certains souhaitaient l'intégration dans C++ d'un mécanisme de ramasse-miettes (garbage collector = gestion automatique de la mémoire), mécanisme déjà présent dans des langages comme LISP. Finalement la technique d'acquisition de ressources par initialisation s'est imposée face à cette approche.


L'efficacité (libération de ressource immédiate), la robustesse et l'universalité (pas uniquement utilisable pour la mémoire) de l'acquisition de ressources par initialisation explique que, bien qu'il existe de bonnes solutions de ramasse-miettes pour C++, ces dernières ne soient jamais devenues populaires.


La technique repose sur la création d'objet dans le tas (heap) et sur un mécanisme de destructeurs appelés automatiquement. Si C++ connaît ces notions, des langage moins complets comme Java ne permettent pas de mettre en place cette technique, il faut alors se contenter du ramasse-miette.


L'article sur Wikipedia

Les pages c++ de Bjarne Stroustrup, voir en particulier les FAQs

Illustrons le mécanisme avec un classe SDEST supposée représenter une chaîne de caractères.


class SDEST
{
private:
  char *ptr;
public:
  SDEST() : ptr(0)
   {
      if( (ptr = (char *)malloc(128)) == 0 )
         throw mon_exception("mémoire insuffisante");
   }

  ~SDEST()
   {
     if( ptr ) free(ptr);
   }

   SDEST operator << (const char *s);
   // Opérateur de concaténation sensé gérer automatiquement
   // l'allocation de mémoire supplémentaire si besoin.
};

La classe SDEST respecte le paradigme RAII, car les ressources pouvant être allouées par ses fonctions membres sont systématiquement libérées par le destructeur.


Examinons maintenant une utilisation de la classe SDEST


{
  SDEST str;  // création dans le tas d'une chaîne.
              // L'allocation mémoire et l'utilisation de
              // pointeurs est transparente
   str << "Bonjour les amis"; 
      // le grossissement de l'espace mémoire éventuellement
      // nécessaire est géré automatique
    
} // str est détruit automatiquement, la mémoire str.ptr est libérée

On notera que :
- Aucun pointeur n'apparaît (ce qui n'aurait pas été le cas si on avait crée l'objet str avec un new

- Les ressources sont automatiquement libérées, y compris si d'autres traitements (non écrits dans l'exemple) provoquent une exception après la création de l'objet str

- il n'est pas besoin d'écrire du code pour libérer les ressources. En corollaire, la gestion d'exception (try ... catch ...) ne sert plus à faire du nettoyage. On a à écrire une gestion d'exception si et seulement si on veut traiter l'erreur, le nettoyage est lui automatique


Tout cela augmente grandement la robustesse et la simplicité du programme.


L'acquisition par construction n'est pas limitée à la mémoire, mais elle s'applique aux ressources en général. En voici un exemple :


 {
    MUTEX mux("mymux.mux"); // acquisition d'une sémaphore UNIX

    ... code critique (protégé contre un accès simultané)...

 } // libération automatique

Comparons maintenant un même programme avec est sans RAII.


La méthode traditionnelle :


{
  FICHIER *f = 0;
  try
    {
    f = new FICHIER("monfichier.txt");
      
          ...
     delete f; f = 0;
    }
  catch( ... )
    {
    if( f ) delete f;
    throw;
    }
}

Le même programme avec l'acquisition par initialisation est aussi robuste mais d'une structure plus simple et moins sujette à erreur :


{
  FICHIER f("monfichier.txt");
    
    ...

}

Voici quelques règles :

- toute acquisition de ressource doit être encapsulée selon le principe de la RAII.

- on écrira avec soin les destructeurs des classes utilisant la RAII

- Il ne faut pas oublier que, si un constructeur ne se termine pas avec succès, alors le destructeur correspondant ne sera jamais appelé. On devra donc gérer le cas des objets partiellement construits, en écrivant éventuellement des gestion d'exception de nettoyage dans les constructeurs d'un objet allouant plusieurs ressources (une autre solution consiste à créer d'autre classes encapsulant l'allocation de ressources selon le principe une classe = une ressource).

Rétroliens

Laurence et Sébastien Dubourg sur : LDAP

Show preview
LDAP (Lightweight Directory Access Protocol) est un protocole réseau relatif à des annuaires informatiques. La RFC1823 propose en outre une API (interface de programmation) normalisée d'accès aux annuaires LDAP. Voici quelques références utiles pour q

Laurence et Sébastien Dubourg sur : Comment empécher l'allocation dynamique d'un objet en C++

Show preview
Technique trouvée sur un blog consacré à l'informatique : on ne fait pas de la magie. Pour interdire l'allocation dynamique d'un objet, il suffit de définir un opérateur new() comme ci-dessous pour la classe de l'objet. class maClasse { public:

Commentaires

Afficher les commentaires en Vue non groupée | Vue groupée

Pas de commentaires

Ajouter un commentaire

Marquer un texte en gras: *mot*, souligner un texte: _mot_.
Les smilies standard comme :-) et ;-) sont convertis en images.
:'(  :-)  :-|  :-O  :-(  8-)  :-D  :-P  ;-) 
Les adresses Email ne sont pas affichées, et sont seulement utilisées pour la communication.

Pour éviter le spam par des robits automatisés (spambots), merci d'entrer les caractères que vous voyez dans l'image ci-dessous dans le champ de fomulaire prévu à cet effet. Assurez-vous que votre navigateur gère et accepte les cookies, sinon votre commentaire ne pourra pas être enregistré.
CAPTCHA

Form options