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 :

liste de pointeurs, détruire un objet


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 6
    Points : 5
    Points
    5
    Par défaut liste de pointeurs, détruire un objet
    Bonjour,

    Je suis en train de faire un mini-projet en C++ pour apprendre à me servir convenablement de Qt, cependant j'ai un petit problème (mais rien à voir avec Qt, la doc est plutôt bien faite )


    Synthétiquement, voila ce que j'ai :

    J'ai une classe A et une classe B.
    A contient une liste de pointeurs sur des objets de type B.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A
    {
         std::list<B*> laListe;
     public:
         A();
    }
     
    class B
    {
         B();
         void detruire();
    }

    Et je voudrais tout simplement pouvoir faire en sorte de lorsqu'un objet B soit supprimé, son pointeur dans la liste de A disparaisse.

    J'ai essayé avec un destructeur de B mais je n'y arrive pas, l'objet B est toujours accessible dans la liste :/


    Mon problème me semble vraiment très simple, c'est d'autant plus frustrant
    J'espère que vous pourrez m'éclairer là dessus, merci d'avance.

  2. #2
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 534
    Points : 6 723
    Points
    6 723
    Par défaut
    Bonjour,

    si une instance de B connait la/les instance(s) de A qui le référence il suffit de définir une opération sur A retirant l'instance, cette opération étant appelée par le destructeur de B (attention si une elle instance de A est détruite avant l'instance de B ). Bien évidemment si laListe est un attribut de classe c'est encore plus simple.

    Mais puisque vous utilisez Qt il peut être plus simple d'utiliser les signaux/slots
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    En effet ça répond bien à ma question, je pourrais donc créer un pointeur dans B qui réfèrerais à l'objet dans lequel il est listé, puis utiliser cette variable pour retirer B de la liste.

    Mais oui, au final je vais utiliser des un signal et un slot, ça sera sûrement plus propre ... Je dois aimer me compliquer la vie

    Merci pour votre réponse (rapide en plus )

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Salut,

    Pour commencer, je voudrais te mettre en garde sur une éventuelle fonction détruire qui ne serait pas statique...

    Typiquement, la destruction est dévolue... au destructeur de la classe

    Ceci dit, il y a deux solutions, chacune ayant ses avantages et ses inconvénients:

    1- La première est d'utiliser un pointeur sur le contenant (ta classe A) dans ton contenu (ta classe B) et de prévoir une fonction remove( B*) dans la classe A.

    Il te "suffit" alors:
    • de transmettre le pointeur sur l'instance de type A qui contient ton objet de type B dans son constructeur (ou de prévoir, si le "propriétaire" de ton objet peut être redéfini, un mutateur sur le pointeur)
    • d'invoquer la fonction remove au départ du pointeur membre directement dans le destructeur de B.


    Cela donne un code proche de
    la classe B
    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
    class A; // déclaration anticipée
    class B
    {
        public:
            B(A* h /* autres paramètres éventuels*/):holder_(h){}
            /* Attention, le destructeur doit normalement être défini après inclusion
             * de A.h... je ne le présente ici que "par flegme" :D
             */
            ~B()
            {
                if(holder_)
                    holder_->erase(this);
            }
            /* éventuellement */
            void defineHolder(A* ptr)
            {
                /* évitons d'avoir plusieurs propriétaires pour un seul pointeur */
                if(holder)
                    holder_->erase(this);
                holder_=ptr;
            }
        private:
            A* holder_;
    };
    la classe A
    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
    class B; 
    class A
    {
        public:
            /* ici aussi, toutes les fonctions qui invoquent un comportement
             * de B devraient être définies après inclusion de B.h...
             * Meme cause, memes effets :D
             */
           ~A()
           {
               for(std::list<B*>::iterator it=items_.begin(); it!=items_.end();
                   ++it)
                   delete (*it); // nous aurions pu utiliser une classe helper 
                                 // et foreach ;)
           }
           void remove(B* ptr)
           {
               std::list<B*>::iterator it=items_.begin();
               /* nous aurions pu utiliser remove_if ;) */
               while(it!=items_.end())
                   if( (*it)==ptr)
                       items_.remove(it);
           }
        private:
            std::list<B*> items_;
    };
    NOTA: il est également possible d'envisager que A soit un singleton avec cette solution

    2- La deuxième solution consiste à faire que la décision de la destruction d'un des élément contenus (un objet de ta classe B) revienne... au contenant (la classe A).

    Pour éviter tout risque de voir quelqu'un de bien intentionné faire une bêtise en essayant de libérer la mémoire allouée au pointeur sur B de manière indue, il est possible de déclarer le destructeur de B comme private (ou protected, si B est destiné à entrer dans une hiérarchie d'héritage) et de déclarer A comme classe amie de B.

    Cela prendrait la forme de
    La classe A
    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
    class B
    class A
    {
        /* allez, amusons nous :D */
        struct deleter
        {
            void operator()(B* ptr)
            {
                delete ptr;
            }
        }
        public:
            ~A()
            {
                for_each(items_.begin(),items_.end(),deleter());
            }
            /* supprime le B indiqué et... le détruit correctement */
            void erase(B* ptr)
            {
                deleter(ptr);
                remove_if(items_.begin(),items_.end(),bind2nd(equal_to<B*>(), ptr));
            }
        private:
            std::list<B*> items_;
    };
    La classe B
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A;
    class A::deleter;
    class B
    {
        /* tout se joue ici :D*/
        friend class A::deleter;
        private:
            ~B(){} //et ici
    };
    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

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    la deuxième me solution me semble moins bonne que la première, je préfèrerais que l'objet B se "détruise" lui même, qu'il soit plus autonome.

    Par contre la première est parfaite, j'avais à chaque fois un erreur de compilation ... a.h incluait b.h et réciproquement, b.h incluait a.h, et ça causait un problème. Alors qu'avec la déclaration anticipée de A dans b.h je n'ai plus cette erreur (je fais donc l'include de a.h dans b.cpp).

    Bref j'ai compris comment ça marche, et mon problème est résolu.
    Merci beaucoup

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    Citation Envoyé par Kush. Voir le message
    la deuxième me solution me semble moins bonne que la première, je préfèrerais que l'objet B se "détruise" lui même, qu'il soit plus autonome.
    Et pourtant... La seconde solution est souvent bien meilleure que la première: il est de bon ton de faire en sorte que la destruction d'un objet dépende... de son propriétaire
    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
    Futur Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    6
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 6
    Points : 5
    Points
    5
    Par défaut
    Ah

    J'ai encore beaucoup à apprendre ...

    Mais ça me semble bizarre puisque dans mon projet, la classe B est une classe Batiment, et la classe A est une classe Joueur.
    Donc quand le bâtiment n'a plus de vie il me semblait plus logique qu'il se détruise lui même :/
    Mais peut-être que j'adapte trop la conception de mon programme à la réalité ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 626
    Points : 30 684
    Points
    30 684
    Par défaut
    En fait, le bâtiment devrait envoyer un signal indiquant "je suis mort" à son propriétaire (ou le propriétaire doit régulièrement demander aux différents batiemens "es-tu encore vivant ?"), et le propriétaire devait alors réagir en:

    1- libérant la mémoire du pointeur
    2- supprimant le pointeur de la liste

    En effet, un objet a rarement le choix de se détruire lui-même (comme disait schwatzeneger "je ne peux pas m'auto-terminer")... Au mieux a-t-il la possibilité de signaler qu'il est dans un état qui implique qu'il doit être détruit
    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

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

Discussions similaires

  1. Réponses: 4
    Dernier message: 28/03/2014, 09h56
  2. fuite de memoire dans une liste de pointeur sur composant
    Par Nicolos_A dans le forum Composants VCL
    Réponses: 2
    Dernier message: 16/12/2004, 08h46
  3. [Ada] Récupérer un pointeur sur un objet existant
    Par vincnet500 dans le forum Ada
    Réponses: 1
    Dernier message: 14/11/2004, 14h26
  4. vector de pointeurs sur des objet
    Par jean-bobby dans le forum SL & STL
    Réponses: 26
    Dernier message: 06/08/2004, 14h54
  5. [LG]liste chainee + pointeur + affichage
    Par k_ro dans le forum Langage
    Réponses: 6
    Dernier message: 17/01/2004, 13h58

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