Résumé : Chap 1 – RAII et gestion moderne des ressources
La gestion manuelle des ressources impose au programmeur de veiller lui-même à leur libération. Une allocation réalisée avec new ou new[] doit ainsi être suivie du delete correspondant, quel que soit le chemin suivi par le programme.
Une sortie anticipée d’une fonction, une erreur ou une exception peut empêcher l’exécution de cette libération et provoquer une fuite de mémoire.
Une ressource ne désigne pas uniquement de la mémoire dynamique. Il peut également s’agir d’un fichier ouvert, d’une connexion réseau, d’un socket, d’un verrou, d’une connexion à une base de données ou de toute autre ressource qui doit être acquise, utilisée puis libérée.
RAII, Resource Acquisition Is Initialization, associe la durée de vie d’une ressource à celle d’un objet qui en devient responsable.
L’objet acquiert généralement la ressource lors de sa construction et la conserve pendant toute sa durée de vie. Son destructeur assure ensuite sa libération.
La destruction des objets automatiques étant prise en charge par le langage, la libération de la ressource ne dépend plus d’une instruction placée explicitement à un endroit particulier du programme.
Lorsqu’une fonction se termine normalement, les objets locaux sont détruits et leurs ressources sont libérées.
Le même mécanisme intervient lors d’un return anticipé : avant de quitter la portée, le C++ détruit les objets locaux dont la durée de vie se termine.
RAII intervient également lors de la propagation d’une exception. Pendant le stack unwinding, les objets automatiques déjà construits sont détruits conformément aux règles du langage et leurs ressources sont ainsi libérées.
RAII ne signifie pas que toutes les ressources sont placées sur la pile. Un objet automatique peut parfaitement gérer une zone de mémoire obtenue dynamiquement. C’est la responsabilité de la ressource qui est associée à l’objet.
RAII ne se limite donc pas à placer un delete dans un destructeur. Il établit une relation entre un objet propriétaire et la ressource dont il contrôle la durée de vie.
Cette notion de propriété devient essentielle lorsqu’un objet est copié. Copier un pointeur copie son adresse, mais ne copie pas la ressource qu’il désigne.
Deux objets peuvent alors se retrouver avec la même adresse et considérer chacun qu’ils sont propriétaires de la même ressource. Leur destruction peut provoquer une double libération et conduire à un comportement indéfini.
Une classe possédant directement une ressource doit donc définir précisément le comportement de la copie, de l’affectation, du déplacement et de la destruction.
Le C++ moderne fournit des objets spécialisés qui appliquent RAII et expriment explicitement la propriété des ressources.
Parmi eux, std::unique_ptr représente une ressource possédant un propriétaire unique et empêche les copies susceptibles de créer plusieurs propriétaires de la même ressource.
RAII constitue ainsi le fondement de la gestion moderne des ressources en C++ : la ressource reste bien présente, mais sa gestion est confiée à un objet dont le langage contrôle la durée de vie.