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 :

pointeur nu avec new ou smart pointer?


Sujet :

C++

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut pointeur nu avec new ou smart pointer?
    Bonjour,

    je sais c'est mal, mais je n'ai jamais vraiment utilisé les pointeurs intelligents. En fait je n'en avais jamais vraiment eu besoin.
    Mais là je pense que je suis enfin tombé sur un cas où il serait peut-être préférable de l'utiliser.
    J'ai un sequénceur qui possède une queue d'événements, événements qui sont ajoutés par pointeurs:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    static void Sequencer::AddEvent( Event* );
     
    // qui sera appelé comme suit (normalement):
    Sequencer::AddEvent( new MonEvent( mes_params ) );
    Ledit séquenceur efface les événements après les avoir consommés:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    void Sequencer::OnTick()
    {
       pour tous les events qu'il faut exécuter:
          execute event
          delete event 
    }
    Or maintenant, il se trouve que je veux avoir un objet qui va déclancher un événement de temps en temps. Il aura donc un événement stocké en tant que variable membre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class UnTruc
    {
    private:
      Event * mon_event;
     
    public:
      // constructeur
      UnTruc(mes_params) : mon_event( new Event( mes_params) ) {} 
     
      // des paramètres et fonctions...
    };
    Et donc, de temps en temps, je vais avoir des trucs du style:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void UnTruc::FaitQuelqueChose()
    {
       // fait quelque chose
       Sequencer::AddEvent( mon_event );
    }
    Le problème, comme vous le voyez, avec le code ci-dessus, c'est que l'événement mon_event sera effacé par le séquenceur aprés avoir été exécuté. Et donc la prochaine fois que UnTruc::FaitQuelqueChose() sera appelé, mon_event sera invalide et j'aurai un comportement indéterminé (avec, le plus probablement, un zoli crash).

    Donc, la première solution consiste à copier le pointeur lors de l'ajout:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Sequencer::AddEvent( new Event( mon_event ) );
    Mais ça implique, entre autres, qu'il faut s'assurer que cette copie se passe bien, ce qu'il n'est pas forcément assuré.

    Et en fait, de toute façon le problème c'est que en fonctionnant ainsi, je suis constamment exposé à cette erreur (ajouter un événement qui va se faire delete par le séquenceur) au cours de mon developpement sur ce programme.

    Ma question est donc: dans ce cas précis, serait-une bonne chose d'utiliser un smart pointer? Si oui, quel type de smart pointer?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  2. #2
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    je ne suis qu'un débutant, mais , je te conseillerais boost::shared_ptr dans ton cas précis, et je trouve que c'est une très bonne idée que de résoudre ton problème de la sorte (pourquoi être contre les smart pointers ? contre auto_ptr ok mais sinon ?)


    tu pourra effacer ta copie de pointeur à chaque fois que son évènement sera consommé, mais comme il restera un pointeur sur ton evenement (ton attribut), il me semble qu'il ne détruira pas ton objet, juste le pointeur.

    Mais tout cela à confirmer auprès des plus expérimentés

    bonne journée,
    Nullius in verba

  3. #3
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par r0d Voir le message
    je sais c'est mal, mais je n'ai jamais vraiment utilisé les pointeurs intelligents. En fait je n'en avais jamais vraiment eu besoin.
    On passe tous par là.
    Tant qu'on ne s'en est pas servi, on conserve ses anciennes habitudes parce qu'on ne sait pas trop comment ils fonctionnent.
    Et une fois qu'on a essayé, on se rend compte à quel point c'est puissant !


    Donc l'utilisation des shared_ptr me paraît en effet appropriée.
    Que ce soit boost::shared_ptr, std::tr1::shared_ptr avec le TR1 du C++0x ou std::shared_ptr avec le C++11...
    Le séquencer a la responsabilité de détruire les événements consommés, mais il se peut qu'un des événements doivent rester valide.
    C'est bien un cas de ressources partagées.

    Pour leur utilisation, ça va aller ou tu veux des conseils ?


    L'alternative au pointeurs intelligents serait de faire quelque chose comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void UnTruc::FaitQuelqueChose()
    {
       // fait quelque chose
       Sequencer::AddEvent( new Event(mon_event) );
    }
    ou
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void UnTruc::FaitQuelqueChose()
    {
       // fait quelque chose
       Sequencer::AddEvent( mon_event->clone() );
    }

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par r0d Voir le message
    je sais c'est mal, mais je n'ai jamais vraiment utilisé les pointeurs intelligents.
    Ca dépend. Si tu sais toujours bien préoccuper de la propriété de tes ressources et de leur durée de vie, l'absence de smart pointeur est surtout embêtante par rapport aux problématiques RAII (mais si sur exception tu choisis de cracher ton appli...). Cf le (excellent) dernier billet d'Emmanuel.

    Citation Envoyé par r0d Voir le message
    Ma question est donc: dans ce cas précis, serait-une bonne chose d'utiliser un smart pointer? Si oui, quel type de smart pointer?
    Ben va falloir choisir qui gère le pointeur. Le séquenceur ou celui qui lui donne ? Si la réponse est les deux => ben, alors 2 interfaces:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    struct sequenceur
    {
    public:
       void AddYourEvent(Event*e_)
       {
          the_evt.push_back(std::make_pair(e_,false));
       }
     
       void AddMyEvent(Event*e_)
       {
          the_evt.push_back(std::make_pair(e_,true));
       }
     
    private:
       typedef std::pair<Event*,bool> t_event;
       std::list<t_event> the_evt;
    };
    Mais tu resteras toujours exposé aux exceptions

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Merci pour vos réponses.

    Après avoir lu attentivement et assimilé vos messages, voici une façon de synthétiser le problème:

    Je pense qu'il serait plus logique que ce soit le séquenceur qui possède le pointeur qu'on lui donne. C'est à dire qu'au moment du AddEvent(), la responsabité du pointeur doit être donnée au séquenceur. Cela me semble plus logique parce que l'idée du séquenceur c'est qu'à n'importe quel moment et n'importe où dans mon programme on puisse accéder à ce séquenceur et lui dire "tiens, tu vas m'exécuter telle action à tel moment", puis continuer l'exécution sans plus du tout se préoccuper de cette action (événement).

    En fait je me rend compte que je n'ai jamais eu besoin des pointeurs intelligents car selon ma façon de voir les choses, un objet, qu'il soit sur la pile ou sur le tas, doit toujours avoir un responsable (ou propriétaire) bien déterminé. Plus qu'une question de gestion de la mémoire, c'est une question de logique lors de la construction du programme, une façon de savoir toujours clairement qui est responsable de qui. Plus un confort de programmation qu'un idiome technique, si vous voyez ce que je veux dire.

    Donc en fait, en bref, j'ai l'impression que finalement, l'utilisation d'un smart pointeur n'est peut-être pas la solution ici. La bonne solution serait de forcer la copie de l'événement à l'appel du AddEvent. Vous ne croyez pas?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  6. #6
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 614
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut,
    Citation Envoyé par r0d Voir le message
    Merci pour vos réponses.

    Après avoir lu attentivement et assimilé vos messages, voici une façon de synthétiser le problème:

    Je pense qu'il serait plus logique que ce soit le séquenceur qui possède le pointeur qu'on lui donne. C'est à dire qu'au moment du AddEvent(), la responsabité du pointeur doit être donnée au séquenceur. Cela me semble plus logique parce que l'idée du séquenceur c'est qu'à n'importe quel moment et n'importe où dans mon programme on puisse accéder à ce séquenceur et lui dire "tiens, tu vas m'exécuter telle action à tel moment", puis continuer l'exécution sans plus du tout se préoccuper de cette action (événement).
    Cela semble, effectivement, logique... Surtout si tu pars du principe que la responsabilité du séquenceur est de "gérer les événements qu'il reçoit" .
    En fait je me rend compte que je n'ai jamais eu besoin des pointeurs intelligents car selon ma façon de voir les choses, un objet, qu'il soit sur la pile ou sur le tas, doit toujours avoir un responsable (ou propriétaire) bien déterminé. Plus qu'une question de gestion de la mémoire, c'est une question de logique lors de la construction du programme, une façon de savoir toujours clairement qui est responsable de qui. Plus un confort de programmation qu'un idiome technique, si vous voyez ce que je veux dire.
    je ne peux qu'approuver
    Donc en fait, en bref, j'ai l'impression que finalement, l'utilisation d'un smart pointeur n'est peut-être pas la solution ici. La bonne solution serait de forcer la copie de l'événement à l'appel du AddEvent. Vous ne croyez pas?
    Personnellement, je suis plutot d'accord avec ce point de vue, il faut "juste" s'assurer que la duplication de l'événement
    1. se fasse correctement (n'oublie pas que l'événement a une sémantique d'entité )
    2. ne demande pas trop de ressources, et surtout, pas trop de temps...
    N'oublie pas que tu seras sans doute parti pour créer des événements " à tire la rigo" pour les envoyer vers le séquenceur...

    Si les événements ont un délais de duplication trop important, tu risque de voir s'effondrer les perfomances
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    La première question que je me poserais, c'est pourquoi des pointeurs ? Pourquoi ne pas gérer ces events par valeuren les copiant d'un endroit à l'autre ?

    S'il y a une bonne raison de le faire, ma seconde question est alors : Pourquoi gérer par copie les events particulier qui ont comme objectif de survivre à un appel ? Si la copie des events pose problème, elle pose probablement problème partout. Donc les solutions à base de "je copie de temps en temps" me semblent suspectes.

    Je ne suis pas d'accord avec l'article d'Emmanuel, j'ai déjà donné mon avis en commentaire, et je trouve qu'on se retrouve précisément dans le cas dont je parlais : Afin de conserver un certain idéal artistique de possession unique, on se retrouve à essayer de tordre le design initial (par exemple la solution de 3DArchi qui demande à l'utilisateur de changer le code d'enregistrement d'un event le jour où l'on décide qu'on va vouloir émettre l'event plusieurs fois, qui ne respecte donc pas l'OCP ).

    Je ne considère pas pour ma part la possession unique comme un principe de design, et un shared_ptr me satisfait totalement dans cet exemple comme dans d'autres.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    La première question que je me poserais, c'est pourquoi des pointeurs ?
    Pour bénéficier du polymorphisme. Je pourrais ajouter une couche d'indirection, mais cela en vaut-il la peine?

    Citation Envoyé par JolyLoic Voir le message
    S'il y a une bonne raison de le faire, ma seconde question est alors : Pourquoi gérer par copie les events particulier qui ont comme objectif de survivre à un appel ? Si la copie des events pose problème, elle pose probablement problème partout. Donc les solutions à base de "je copie de temps en temps" me semblent suspectes.
    Ben en fait, c'est ce que je disais précédemment: la solution serait peut-être finalement de forcer la copie à chaque fois. Après reste à voir la conséquence que ça a niveau performances, mais dans mon cas précis, cela devrait être négligeable car les évenements seront quasiment vides.

    Citation Envoyé par JolyLoic Voir le message
    Je ne considère pas pour ma part la possession unique comme un principe de design.
    Moi non plus. Je le considère comme un confort. C'est un peu "dirigiste" comme façon de voir les choses: aucune instance n'est libre. Ca force parfois à faire des "managers de ressources", ou des médiateurs, ce qui donne du code très centralisé, mais ça permet d'avoir une controle fort sur la gestion de la mémoire et ainsi de faciliter les phases de debug et d'optimisation.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

Discussions similaires

  1. Réponses: 0
    Dernier message: 16/06/2014, 17h08
  2. Réponses: 7
    Dernier message: 17/11/2011, 10h16
  3. references, pointeurs, smart pointer ?
    Par Elay dans le forum C++
    Réponses: 6
    Dernier message: 13/10/2010, 22h30
  4. Réponses: 5
    Dernier message: 22/04/2005, 11h38
  5. templates et smart pointers
    Par delire8 dans le forum C++
    Réponses: 9
    Dernier message: 10/07/2003, 16h26

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