IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Question sur le RAII


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Février 2020
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Santé

    Informations forums :
    Inscription : Février 2020
    Messages : 12
    Par défaut Question sur le RAII
    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 :

    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);
    }
    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
    9
    void traitement()
    {
        auto tableau = std::vector<int>{};
        auto objet = createObjet();
     
        tableau.at(0) = 7;
     
        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.

    Autre cas :

    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;
    }
    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é.

    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 :

    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;
    }
    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;.

    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 :

    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;
    };
    Et maintenant, si on utilise toujours ObjetCPP et plus Objet*, on n’aura plus jamais de fuite de mémoire !

    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.

  2. #2
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 487
    Par défaut
    Comme on n'a même pas ni la déclaration ni la définition de ces 2 fonctions ni les choses qui ont été abordées précédemment dans le tutoriel, on ne peut faire que des suppositions à 2 balles.

    Voilà la mienne : passage par référence non const.

    signature des méthode avant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bool aBesoinDeTraitement(Objet* toto);
    int traiterObjet(Objet* toto);
    signature des méthode après :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    bool aBesoinDeTraitement(ObjetCPP& toto);
    int traiterObjet(ObjetCPP& toto);
    Mais bon, utilisez des pointeurs nus dans ce type d'exemple, c'est donner le "mauvais exemple".

    P.S.: "smart pointeur + deleter custom", j'y crois pas, il aurait présenté les smart pointeurs avant de donner des exemples tout pourri de librairie "C".

  3. #3
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Février 2020
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Santé

    Informations forums :
    Inscription : Février 2020
    Messages : 12
    Par défaut
    ces tutos sont ici:
    https://koor.fr/Cpp/RAII/Index.wp
    j'étais au java et j'aime vraiment plus ça, les api comme hibernate etc.. les sgbd etc.. ça me soule.
    alors j'ai repris c/c++ que j'avais un peut commencé y'a très longtemps et concernant la libération de
    ressources par le raii: je suis un peut perplex et je vais voir d'autres tutos sur le sujet, les siens m'ont
    parfois aidé mais pas toujours alors......
    merci

  4. #4
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 766
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 766
    Par défaut
    Je ne vois pas le code posté dans ce tutoriel

    Citation Envoyé par suzut Voir le message
    je suis un peut perplex
    Pourquoi ? explique.

    1 truc me dérange dans le code
    Ce code :
    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);
    }
    C'est du pur code C 1 peu mal fait.
    Je ne parle pas de la faute "createObject" et "freeObject" (mélanger le français et l'anglais )

    C'est du pur code C parce que lorsqu'on crée des structures struct, on crée en même temps 1 interface : createXXX, deleteXXX, initXXX, updateXXX, ...
    Tout ceci afin d'éviter de copier-coller X fois 1 même code très difficilement trouvable avec la recherche (en cas de modifications) : 1 seul endroit dans le code pour répercuter les modifications partout.

    1 peu mal fait, parce qu'on met le nom de la classe à gauche (c'est + 1 préférence personnelle ou dans les coding styles) : object_create, object_delete, object_init, object_update, ...

    Donc je ne vois pas pourquoi cette interface (1) createObject et freeObject se retrouve telle quelle dans le constructeur et le destructeur
    C'est d'ailleurs ce qui fait office de constructeur et de destructeur en C surtout que le code de (1) doit faire appel à malloc et free.

    Après il y a la notion de "lazy initialisation" : en gros l'initialisation de la ressource ne se fait pas dans le constructeur.

    Sais-tu qu'à chaque fois qu'on utilise 1 objet sans pointeur ni référence (paramètre, variable locale, ...), 1 objet est créé ?
    Et donc si on met l'initialisation dans le constructeur, tu construis beaucoup [beaucoup] de ressources.


    Citation Envoyé par suzut Voir le message
    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
    La notion de protected et de virtua sont 2 notions distinctes : l'une n'empèche pas l'autre.
    Surtout que cela va dépendre si tu protèges le destructeur de la classe mère, des classes filles ou de tout le monde.

  5. #5
    Membre averti
    Homme Profil pro
    Administrateur de base de données
    Inscrit en
    Février 2020
    Messages
    12
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Administrateur de base de données
    Secteur : Santé

    Informations forums :
    Inscription : Février 2020
    Messages : 12
    Par défaut
    arrrr !!!! je m'étais trompé de liens GRR désolé :/ c'était ici le code :
    https://nodatek.com/article10/tuto-cpp-le-raii
    & du coup la page s'affiche plus; j'ai testé avec 2 ip; en espèrant que le server se réveillera....

    pour répondre à la question "Sais-tu qu'à chaque fois qu'on utilise 1 objet sans pointeur ni référence (paramètre, variable locale, ...), 1 objet est créé ?
    Et donc si on met l'initialisation dans le constructeur, tu construis beaucoup [beaucoup] de ressources. " ......
    oui, on m'a conseillé d'utiliser les pointeurs ou les références plutôt que les constructeurs par copy

  6. #6
    Expert confirmé
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 487
    Par défaut
    Bon bin, le tutoriel aiguille sur les smart pointeurs et la STL, donc c'est cool.

    Les exemples "en C" sont un peu tout pourri mais c'est un peu un argumentaire à base d'"homme de paille".

    On est sur un tutoriel, pas sur un argumentaire béton contre les vieilleries du C ou du C++ pré-98.

    Et si le C++ avait des choses, en standard, aussi aboutis qu'Hibernate (ou autres ORMs), ça serait trop cool.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [debutant] Questions sur 1 futur projet
    Par cyrull22 dans le forum XML/XSL et SOAP
    Réponses: 3
    Dernier message: 28/04/2003, 21h49
  2. Quelques questions sur le TWebBrowser...
    Par CorO dans le forum Web & réseau
    Réponses: 3
    Dernier message: 17/01/2003, 21h23
  3. Question sur les handles et les couleurs...
    Par MrDuChnok dans le forum C++Builder
    Réponses: 7
    Dernier message: 29/10/2002, 08h45
  4. Réponses: 2
    Dernier message: 11/08/2002, 21h27
  5. question sur les message box !
    Par krown dans le forum Langage
    Réponses: 7
    Dernier message: 02/08/2002, 16h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo