bonjour
je suis sur un tutorial à propos du RAII(j'ai download la page) et il y a une ambiguité à un endroit, je ne comprends pas la " modification dont parle celui qui a fait le tutorial "
je vais copier coller tout le tuto et je cite "Un petit problème subsiste : les fonctions aBesoinDeTraitement et traiterObjet ont besoin d’un pointeur vers Objet et non d’un ObjetCPP. Mais il est relativement simple d’adapter le code pour qu’il fonctionne. " >>> et là quelque chose n'est pas clair et ambigu par rapport à cette modification à effectuer.
La plupart du temps, les bibliothèques C bien écrites permettent de créer des objets via une fonction createObjet, objets qu’il faut ensuite libérer en utilisant une fonction freeObjet.
Lorsqu’on souhaite utiliser un tel objet, on a un code qui peut ressembler à cela :
Ce code a un énorme défaut : il faut toujours penser à libérer notre objet en appelant la méthode freeObjet. C’est déjà source d’erreur. Mais surtout, il faut veiller à ce que cette méthode soit appelée dans tous les chemins d’exécution possibles. Imaginons le code qui suit :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8 int main() { auto objet = createObjet(); // on utilise notre objet freeObjet(objet); }
Ici, la ligne tableau.at(0) = 7 envoie une exception. Cette exception n’est pas attrapée. La méthode freeObjet n’est pas appelée.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9 void traitement() { auto tableau = std::vector<int>{}; auto objet = createObjet(); tableau.at(0) = 7; freeObjet(objet); }
Autre cas :
Ce code vous paraît-il correct ? On a bien pensé à libérer la mémoire dans le cas où le traitement est effectué, mais pas dans le cas du if qui retourne 0. Ce code entraîne donc une fuite de mémoire dans le cas où l’objet n’a pas besoin d’être traité.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12 int traitement() { auto objet = createObjet(); if(!aBesoinDeTraitement(objet)) return 0; auto resultat = traiterObjet(objet); freeObjet(objet); return resultat; }
Le RAII à la rescousse
Mais alors quelle est la solution ? Comment faire en sorte que la ressource soit toujours libérée, quoi qu’il arrive ?
Ce que vous savez peut-être déjà, c’est que pour un objet alloué de façon statique, dans la pile, le destructeur est toujours appelé. C’est pour cette raison qu’une bibliothèque (bien faite) en C++ ne nécessite jamais d’appeler manuellement une méthode de libération de ressource :
Dans le code précédent, avec ObjetCPP une classe C++ bien faite, le destructeur est appelé quoi qu’il arrive : dans le cas où l’objet n’a pas besoin de traitement et ensuite malgré le fait qu’une exception est lancée par la ligne tableau.at(0) = 7;.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13 int traitement() { auto tableau = std::vector<int>{}; auto objet = ObjetCPP{}; if(!aBesoinDeTraitement(objet)) return 0; tableau.at(0) = 7; auto resultat = traiterObjet(objet); return resultat; }
En quoi consiste donc le principe RAII ? Simplement à utiliser ce mécanisme systématiquement lors de l’acquisition de ressource, en encapsulant toutes les ressources dans des classes dédiées à l’acquisition et la libération de chacune d’elles. En d’autres termes, dans notre cas, on peut écrire le code suivant :
Et maintenant, si on utilise toujours ObjetCPP et plus Objet*, on n’aura plus jamais de fuite de mémoire !
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 class ObjetCPP { public: ObjetCPP() { ressource = createObjet(); } protected: ~ObjetCPP() { freeObjet(ressource); } private: Objet* ressource; };
Vous remarquerez que le destructeur est protected (pour rappel, un destructeur doit être protected ou virtual, cf l’une des règles du NVI dans le tuto précédent. J’écrirai peut-être prochainement un article sur cette règle en particulier).
Un petit problème subsiste : les fonctions aBesoinDeTraitement et traiterObjet ont besoin d’un pointeur vers Objet et non d’un ObjetCPP. Mais il est relativement simple d’adapter le code pour qu’il fonctionne.
>>>>>>>>>> quel est cette modification ? j'attends la réponse en vous remerciant.
Partager