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

Boost C++ Discussion :

liste chainée avec Boost


Sujet :

Boost C++

  1. #1
    Membre régulier
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Septembre 2006
    Messages
    41
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Septembre 2006
    Messages : 41
    Points : 78
    Points
    78
    Par défaut liste chainée avec Boost
    Bonjour, je m'initie aux pointeurs intelligents et mon programme crash.
    Voici un code minimaliste de ce que j'essaie de faire:

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
     
    #include <boost/shared_ptr.hpp>
    #include <boost/enable_shared_from_this.hpp>
     
    class Line: public boost::enable_shared_from_this<Line>
    {
    public:
        typedef boost::weak_ptr<Line> Weak_Line;
        typedef boost::shared_ptr<Line> Shared_Line;
     
        Weak_Line _parent;
        Shared_Line _child;
     
        Line(Weak_Line parent = Weak_Line())
        {
            Shared_Line p = parent.lock();
     
            _parent = parent;
            p->_child = this->shared_from_this();
        }
    };
     
     
    int main(int argc, char *argv[])
    {
        Line::Shared_Line l1(new Line());
        Line::Shared_Line l2(new Line(l1));
        Line::Shared_Line l3(new Line(l2));
     
        return 1;
    }
    Ainsi, j'entre en argument dans le constructeur le parent de mon objet, ce qui permet à mon objet de connaître son prédécesseur et de s'enregistrer vis-a-vis de celui-ci comme son suivant.

    Aussi, je sais d'où vient le problème: "this->shared_from_this()" ne supporte pas le fait d'êtrer appellé alors que aucun pointeur shared, n'a encore été créé.

    L'une des solution que j'ai trouvé sur le net est de créer l'objet, puis de l'initialiser. Et à la rigueur, créer une fonction statique qui permet de créer l'objet comme je le souhaite.

    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
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
     
    class Line: public boost::enable_shared_from_this<Line>
    {
     
    public:
        typedef boost::weak_ptr<Line> Weak_Line;
        typedef boost::shared_ptr<Line> Shared_Line;
     
        Weak_Line _parent;
        Shared_Line _child;
     
        Line()
        {
        }
     
        void init(Weak_Line parent = Weak_Line())
        {
            Shared_Line p = parent.lock();
     
            _parent = parent;
            if(p)
                p->_child = this->shared_from_this();
        }
     
        static Shared_Line create(Weak_Line parent = Weak_Line())
        {
            Shared_Line line(new Line());
            line->init(parent);
            return line;
        }
    };
     
     
    int main(int argc, char *argv[])
    {
        Line::Shared_Line l1(new Line());
        l1->init();
     
        Line::Shared_Line l2(new Line());
        l2->init(l1);
     
        Line::Shared_Line l3 = Line::create(l2);
     
        return 1;
    }
    Néanmoins, je souhaiterais faire en sorte que l"initialisation se passe dans le constructeur, est ce quand même possible?

    Sinon, dans mon cas de la fonction 'create", mes objets pouraient heriter de Line. Ce qui fait que ma fonction 'create' n'est pas suffisante en temps que telle et je vais devoir réimplémenté la fonction 'create' pour chaque nouvelle classe comme suit:

    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
    18
    19
     
     
    class RedLine: public Line
    {
     
    public:
        typedef boost::weak_ptr<Line> Weak_RedLine;
        typedef boost::shared_ptr<Line> Shared_RedLine;
     
        RedLine()
        {}
     
        static Shared_RedLine create(Weak_RedLine parent = Weak_Line())
        {
            Shared_RedLine line(new Line());
            line->init(parent);
            return line;
        }
    };
    A la rigueur, il serait possible de faire un template de la méthode, mais je trouve que la syntaxe resterait lourde: Shared_BlueLine bl = BlueLine::create<BlueLine>(parent). Serait il possible de remédier à cela?

    Au final, je pense que le coup du create n'est pas une bonne idée et donc que la seule le constructeur vide suivit de la méthode d'initialisation est viable.
    Je souhaiterais avoir vos avis et suggestions,

    merci d'avance

  2. #2
    Membre à l'essai
    Homme Profil pro
    Inscrit en
    Janvier 2003
    Messages
    4
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations forums :
    Inscription : Janvier 2003
    Messages : 4
    Points : 10
    Points
    10
    Par défaut
    Quelques suggestions pour toi.
    Essaye d'en faire une classe template, ça te permettra d'utiliser ta classe plus facilement. Ensuite, la façon dont tu definis ta classe depend énormément de la façon dont les objets vont être utilisés.

    Comment tu veux representer ta classe: est-ce que tu veux que l'utilisateur passe la classe dans sont integralité, comme la STL représente std::list, ou tu veux que l'utilisateur de ta classe passe un element de ta liste, comme en C.

    Si tu choisis la première option, pas besoin de weak_ptrs, crée ta chaine comme un vecteur et presente des acces aux données. Ça ne te permettra pas de jouer avec les pointers intelligents.
    Si tu choisis la seconde option, utilise les weak_ptrs, et définie ta classe comme etant un element qui peut avoir acces au precedent et suivant.

    Pour repondre à ta question, le constructor pas defaut est la meilleur solution, tu dois rajouter une methode pour rajouter a ta chaine. Si tu decide de faire comme ça, tu n'as pas besoin d'utiliser shared_from_this.

  3. #3
    Membre chevronné

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Avril 2013
    Messages
    610
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Avril 2013
    Messages : 610
    Points : 1 878
    Points
    1 878
    Billets dans le blog
    21
    Par défaut
    Quelques observations:

    1. pour t'initier aux pointeurs intelligents, pas la peine de passer par boost, ils font partie du standard depuis C++11 (avec un petit oubli de make_unique qui n'a été rajouté que dans le standard c++14). Les bons compilateurs implémentent C++11 et souvent C++14

    2. ton problème est d'abord un problème de conception. Les smart-pointers sont faits pour gérer de la mémoire, ils ne sont pas là pour remplacer les pointeurs en toute occasion. Dans le cas d'une liste chaînée, si tu dois modéliser la gestion de la mémoire, comment faire? Le modèle le plus simple est que chaque noeud maintient un std::unique_ptr sur le suivant. Cela résout le problème de la gestion de la mémoire: on delete le premier noeud, on delete tous les autres. Maintenant si la liste est doublement chaînée, comment modéliser le pointeur vers l'élément précédent? Pour répondre à cette question, il faut se demander si la gestion de la mémoire est en cause. Est-ce le cas? A priori non. Donc le pointeur vers le parent est un pointeur simple. Ce modèle permet de préserver un invariant bien pratique: puisque c'est le père qui libère l'enfant, le pointeur de l'enfant vers le père est toujours valide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    template <class T>
    struct Noeud {
      T value;
      std::unique_ptr<Noeud<T>> next;
      Noeud<T>* prec;
      (...)
    };
    La structure liste elle-même sera chargée de lancer la libération de la mémoire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    template <class T>
    class List {
      std::unique_ptr<Node<T>> head;
      Node<T>* tail;
      (...)
    };
    Lorsque tu ajoutes un noeud, pour un constructeur Node(const T& val, Node<T>* father) tu peux avoir une méthode
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Node<T>::addChild(const T& val) {
      next = std::make_unique<Node<T>>(val, this->get()); // C++14 only
      // C++11: Node<T>* n = new Node<T>(val, this-get()); next.reset(n);
    }
    3. Si tu tiens au shared_ptr, je te conseille de trouver un exemple qui cadre mieux car tu ajoutes là aux difficultés de manipulation du couple weak_ptr / shared_ptr le problème de l'appliquer à un cas pour lequel il n'a pas été conçu.

Discussions similaires

  1. Liste chainée avec chaine de caractère
    Par med_alpa dans le forum C
    Réponses: 4
    Dernier message: 03/01/2011, 09h06
  2. Liste chainée avec recherche et modification
    Par the_leader dans le forum C
    Réponses: 1
    Dernier message: 16/01/2010, 12h40
  3. [debutant] pb avec liste Chainée.
    Par FamiDoo dans le forum Débuter
    Réponses: 2
    Dernier message: 19/03/2006, 16h41
  4. Réponses: 2
    Dernier message: 10/10/2005, 02h25
  5. Mal a la tete avec liste chainée d'objet
    Par Raton dans le forum C++
    Réponses: 23
    Dernier message: 03/08/2005, 22h13

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