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 :

shared_ptr et this


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 68
    Par défaut shared_ptr et this
    Bonjour,

    J'ai un petit problème d'utilisation des smart pointers de boost, notamment shared_ptr et weak_ptr. Je précise que c'est ma première "vraie" utilisation des smarts pointers (mes expériences précédentes se limitaient à des tests pour voir un peu comment ça marchait).

    J'essaie de construire une architecture de type DEM (delegate event model), avec quelque chose de très basique pour commencer. Un peu du style :
    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
    class Listener
    {
    public:
        virtual ~Listener() {}
        virtual void onEvent() = 0;
    };
     
    class Source
    {
    public:
        virtual ~Source() {}
        void addListener(Listener*);
        void removeListener(Listener*);
     
    private:
        list<Listener*> listeners_;
    };
    Un Listener peut s'enregistrer auprès d'une Source en appelant addListener() sur celle-ci, et se désenregistrer par removeListener(). La source peut ensuite notifier ses listeners_ quand bon lui semble en appelant leur méthode onEvent(). J'omets volontairement toute notion de type d'évènement, identité de la source, etc...

    Mon problème concerne le fait que lorsqu'un Listener est détruit, il faut bien qu'il soit retiré des listeners_ des différentes Sources auprès desquelles il s'est enregistré. On pourrait penser à un système plus complexe où les Sources écoutent elles-mêmes des évènement du genre DeletionEvent envoyés par leur listeners, mais c'est tordu. Un collègue m'a expliqué qu'en Java ce mécanisme s'obtient typiquement à base de weak references. Je me suis donc dit qu'il suffisait d'utiliser des shared_ptr dans mon programme, et de les passer aux Sources au lieu des pointeurs natifs, pour qu'elles puissent en faire des weak_ptr, afin de pouvoir les virer quand leur expired() retourne false (il me semble que c'est comme ça qu'on utilise les weak_ptr, dites-moi si je me trompe).

    Du coup la déclaration devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class Source
    {
    public:
        virtual ~Source() {}
        void addListener(shared_ptr<Listener>);
        void removeListener(shared_ptr<Listener>);
     
    private:
        list<weak_ptr<Listener> > listeners_;
    };
    Et la méthode addListener() ressemblerait en gros à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void Source::addListener(shared_ptr<Listener> listener)
    {
        listeners_.push_back(weak_ptr<Listener>(listener));
    }
    Et la méthode qui notifie les listeners_ en les parcourant se chargerait de tester leur expired() et de les supprimer si besoin.

    Sa me semble tenir la route. Seulement voilà mon problème : autant le fait d'attacher un listener à une source sera très facile pour un code client qui fait tout par shared_ptr, et aura donc juste à passer ses shared_ptr de listeners à ses sources, autant c'est beaucoup plus difficile si on veut qu'un listener puisse s'enregistrer tout seul. Vu que quand on est dans le code du listener lui-même, on ne peut bien sûr pas faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    source.addListener(this); // ne compile pas
    et encore moins :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    source.addListener(shared_ptr<Listener>(this)); // provoque une catastrophe : this sera détuit à la fin de l'instruction
    Du coup je me retrouve avec des belles idées mais qui sont finalement assez inutile puisqu'il est quand même plus que fréquent dans ce type d'architecture qu'une classe dérivant de Listener décide d'elle-même d'écouter une source ! (c'est presque le cas nominal...).

    Que pensez-vous de ce problème ? Avez-vous déjà été confronté à ce genre de chose ? Je ne suis un habitué ni des smart pointers ni des event models, donc j'avoue être un peu désemparé. J'ai beau être fan de C++, là je dois avouer que ça serait un jeu d'enfant en Java....

    Toute idée sera appréciée.

    Merci d'avance

  2. #2
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    C'est là que mon tuto intervient : boost::enable_shared_from_this<>

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 68
    Par défaut
    Argggg j'avais fait une recherche et regardé la FAQ, mais j'ai zappé les tutos !
    Ce enable_shared_from_this sonne vraiment très bien, je lis ça ce soir à tête reposée et je te donne des nouvelles.

    Merci !

  4. #4
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 68
    Par défaut
    Salut !

    OK j'ai lu la doc de enable_shared_from_this et je comprend mieux les contraintes et possibilités liées à son utilisation. Ca résoud en effet mon problème, sauf pour une utilisation particulièrement pour laquelle j'aimerais quand même trouver une solution, c'est celle où on a besoin de ce smart pointeur dés la contruction de l'objet.

    En effet si j'ai bien compris la doc, la fonction shared_from_this() n'est valable que si l'existe au moins un shared_ptr pointant vers cet objet, comme le dit la doc :
    There must exist at least one shared_ptr instance p that owns t.
    Donc pour moi le code suivant est boggé :

    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 Listener: public enable_shared_from_this<Listener>
    {
    public:
        Listener()
        {
            uneSource.addListener(shared_from_this());
        }
    }
     
    void main()
    {
        shared_ptr<Listener> p(new Listener());
    }
    Si je comprend bien la doc, l'appel qui est fait à shared_from_this() dans le constructeur est erroné, puisqu'on est seulement en train de construire l'objet, et qu'on en a donc pas encore passé la responsabilité au pointeur p de main().... j'ai bon ? Si oui, vois-tu une solution ?

    Merci

  5. #5
    Rédacteur

    Avatar de Matthieu Brucher
    Profil pro
    Développeur HPC
    Inscrit en
    Juillet 2005
    Messages
    9 810
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Développeur HPC
    Secteur : Industrie

    Informations forums :
    Inscription : Juillet 2005
    Messages : 9 810
    Par défaut
    C'est quoi uneSource ? Si c'est un élément passé en paramètre, il est mieux de faire cette action à l'extérieur du constructeur, d'un point de vue conceptuel.

  6. #6
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    68
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2004
    Messages : 68
    Par défaut
    Je vois 3 possibilités (bien qu'il y en ait sûrement d'autres) pour que uneSource ne soit pas une variable passée en paramètre :
    - ça peut être un singleton
    - ça peut être this lui-même (un objet qui s'écoute)
    - ça peut être un membre créé par l'objet lui-même et qu'il souhaite commencer à écouter dés sa construction.

    Personnellement je suis confronté aux 2 premiers cas (le 2è est tordu, je l'admets). J'ai fait une petite recherche sur le sujet et suis tombé là-dessus :
    http://www.nabble.com/enable_shared_...-t1310193.html
    qui renvoie finalement ici :
    http://boost.org/libs/smart_ptr/sp_t...in_constructor

    Les méthodes proposées parlent d'utiliser un shared_ptr avec un null_deleter() (mais c'est plutôt dans le cas d'un object qui peut être alloué sur la pile), d'utiliser une factory, ou d'utiliser intrusive_ptr (pour l'instant je ne vois pas exactement comment).

    Dans mon cas la factory est la seule solution, bien que cela m'oblige a ajouter une contrainte à ma classe mais qui n'est pas bloquante. Je serai en outre obligé de faire une factory template comme expliqué dans le premier lien, car ma classe est censée être dérivée. Je vais également voir si je peux revoir le design général, car quand une classe a trop de contraintes qui font qu'on arrive pas à en faire ce qu'on veut, c'est parfois qu'elle fait trop de choses...

    Merci en tout cas pour l'aide !

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

Discussions similaires

  1. This.value au lieu de document.getElementById('field').value
    Par yoyot dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 04/03/2005, 14h02
  2. [MFC] Pointeur this et fonctions statiques
    Par Yellowmat dans le forum MFC
    Réponses: 5
    Dernier message: 08/02/2005, 10h15
  3. pb de fonction simple (this.form.submit()..)
    Par petitsims dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 14/01/2005, 09h29
  4. type de this
    Par julie29 dans le forum C++
    Réponses: 4
    Dernier message: 30/11/2004, 20h39
  5. [Oracle 9i] Erreur: wrong incarnation of this file
    Par shaun_the_sheep dans le forum Oracle
    Réponses: 5
    Dernier message: 26/11/2004, 10h53

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