Problème <list> destructeur [Résolu]

Signaler
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
-
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
-
Bonjour à tous !  J'espère que quelqu'un pourra m'aider.
Voiloà mon problème:  j'ai créé une classe abstraite (nommons-la A) et deux classes filles (disons B et C), et une autre classe, non abstraite celle-ci (D).  La classe abstraite ressemble à ceci:
class A{
protected:
   A* _parent;  // adresse du parent
   list _liste1;   //liste qui contiendra ensuite des D*
   list _liste2;   //liste qui contiendra ensuite des C*
   ...
public:
   A(A* =NULL);  //le parent est nul par défaut
   A(const A&);
   virtual ~A();
   A& operator=(const A&);
   void ajoutListe1(A*);
   void ajoutListe2(A*);
   void supprimerListe1(A*);
   void supprimerListe2(A*);
   ...
};

Les deux autres classes B et C contienent bien entendu des champs et des méthodes supplémentaires, ainsi que l'implémentation des méthodes virtuelles pures.
Mais j'ai un problème lors de la destruction...

Voici le destructeur que j'ai implémenté:

A::~A(){
   if(!_liste1.empty()){
      list::iterator it=_liste1.begin();
      while(it!=_liste1.end()){
         delete *it;
         it++;
      }
   }
   // idem pour _liste2
   if(_parent!=NULL)
      _parent->supprimerListe2(this);
}

Je n'ai pas encore mis le _parent->supprimerListe1(this), parce qu'avec liste2, quand j'exécute, le destructeur tourne en boucle...

L'implémentation de supprimerListe2 est la suivante:
void A::supprimerListe2(A* arg){
   list::iterator it=_liste2.begin();
   while(it!=_liste2.end()){
      if(*it==arg)
         delete *it;
      it++;
   }
}

Je fais cela pour signaler au parent qu'il dit supprimer l'instance de _liste2.
Quelqu'un a une idée ?  J'ai beau chercher...  J'ai même tenté d'utiliser _liste2.erase(it), mais pas mieux...
J'utilise Dev-Cpp 4.9.9.2.
Merci d'avance !

10 réponses

Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
C'est un pb de récursivité apparemment:

A::~A()   <= Destructeur de A
{
   if(!_liste1.empty()){
      list::iterator it=_liste1.begin();
      while(it!=_liste1.end()){
         delete *it;
         it++;
      }
   }
   // idem pour _liste2
   if(_parent!=NULL)
      _parent->supprimerListe2(this);    <= Appelle d'une fonction qui appelle le destructeur de A
}

La solution éventuelle (bricolage). Et pour des questions de sécurités, évite les itérateurs la car plusieurs fonctions vont manipuler la meme liste.

   A * tmp;
   while(liste1.size() > 0)
   {
        tmp = liste1.front();
         liste1.pop_front();

         delete tmp;
      }

Mais a mon avis, faut que tu revoies la desctruction de tes objects et en détail. Des que t'as des relations parent <-> enfant, c'est délicat.
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

Salut,

Deja y'a une erreur dans ton code car D herite pas de A
 donc tu peux  pas faire list pour une liste qui va contenir du D
Autre chose : tu as pas une methode clear dans list ? pour faire juste list.clear sans passer par un iterateur ?

Dev cpp est tjrs en mise a jour ?

=
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
2
Oui, juste, tu as raison, mais ce n'est pas ce que j'ai implémenté en réalité, les classes protent d'autres noms, mais comme c'est bcp plus complexe dans mon code, j'ai résumé...  Donc au lieu de list _liste1, il faut lire list<D*> _liste1 et void supprimerListe1(D*) au lieu de void supprimerListe1(A*)...
Le problème de clear, c'est qu'il efface toute la liste.  Ors, je voudrais ne supprimer que l'élément que je passe en paramètre...
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

RE

Essaie de mettre des cout dans ton code pour voir ou ca plante et pourquoi ca boucle

=
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
2
Voilà où il boucle: quand je fais le delete *it dans supprimerListe2, il appelle le destructeur de A, et comme il arrive à la condition (_parent!=NULL) qui se vérifie, il boucle.  J'ai essayé d'ajouter, avant le delete, (*it)->parent=NULL, mais là, j'ai un core dump...
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
2
Si tu veux plus de détails sur ce ue je cherche à faire, je peux expliquer, mais c'est long...  Je peux aussi t'envoyer mes sources si tu m'envoies ton mail en PV...
Messages postés
317
Date d'inscription
vendredi 25 mai 2007
Statut
Membre
Dernière intervention
19 octobre 2007

RE

Comme je hais les destructeurs implicites :p

Ben dans la fonction d'effacement de l'objet  il s'efface de la liste
mais en s'effacant de la liste il efface l'objet et ca recommence
et ca boucle donc.

luthor a repondu ensuite :p mais je comprend mieux ce qui deconnait..


=
Messages postés
2023
Date d'inscription
mardi 24 septembre 2002
Statut
Membre
Dernière intervention
28 juillet 2008
5
Mais il faut absolument empecher l'appel de deux destructeurs sur le meme object, car ca menera a rien de bon. Il ne faut pas juste empecher l'appel récursif.
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
2
Je viens de venir lire vos réponses en vitesses.  Je n'ai pas le temps avant ce soir de tester la solution de luthor, mais je le fais dès que je rentre et je dis ce qui se passe.
Merci encore pour votre aide !
Messages postés
286
Date d'inscription
vendredi 5 décembre 2003
Statut
Membre
Dernière intervention
22 avril 2012
2
Voilà, j'ai trouvé une solution, mais je ne sais pas si elle est réellement valable...  Mais en tout cas, elle fonctionne.  J'ai en partie utilisé le bout de code de luhtor
Je vous l'expose:
Le destructeur de A devient:
A::~A(){
   //traitement liste1;
   if(!liste2.empty()){
      A* tmp;
      while(liste2.size()>0){
         tmp=liste2.front();
         liste.pop_front();
         delete tmp;
      }
   }
   if(_parent!=NULL)
      _parent->supprimerListe2(this);
}

Il a en effet fallu supprimer l'itérateur, parce que supprimerListe2 modifie la liste dans la boucle du destructeur=>core dump...
J'ai ajouté également ceci à supprimerListe2:
A::supprimerListe2(A* arg){
   ...
   if(*it==arg){
      (*it)->_parent=NULL;
      delete *it;
      _liste2.erase(it);
   }
}

Maintenant, ça fonctionne sans plantages, il passe bien par les bons destructeurs quand il faut !
S'il y a moyen d'améliorer ce fonctionnement, je suis ouvert à toute proposition.  Personnellement, je ne vois pas trop...
Encore merci à tous pour votre aide !