Problème <list> destructeur

Résolu
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 - 1 juin 2007 à 11:31
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 - 4 juin 2007 à 13:01
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

luhtor Messages postés 2023 Date d'inscription mardi 24 septembre 2002 Statut Membre Dernière intervention 28 juillet 2008 6
1 juin 2007 à 13:36
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.
3
The_Guardian Messages postés 317 Date d'inscription vendredi 25 mai 2007 Statut Membre Dernière intervention 19 octobre 2007 1
1 juin 2007 à 11:57
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 ?

=
0
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 1
1 juin 2007 à 12:13
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...
0
The_Guardian Messages postés 317 Date d'inscription vendredi 25 mai 2007 Statut Membre Dernière intervention 19 octobre 2007 1
1 juin 2007 à 12:20
RE

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

=
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 1
1 juin 2007 à 12:54
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...
0
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 1
1 juin 2007 à 12:55
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...
0
The_Guardian Messages postés 317 Date d'inscription vendredi 25 mai 2007 Statut Membre Dernière intervention 19 octobre 2007 1
1 juin 2007 à 13:50
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..


=
0
luhtor Messages postés 2023 Date d'inscription mardi 24 septembre 2002 Statut Membre Dernière intervention 28 juillet 2008 6
1 juin 2007 à 13:58
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.
0
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 1
2 juin 2007 à 09:57
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 !
0
cs_exar Messages postés 286 Date d'inscription vendredi 5 décembre 2003 Statut Membre Dernière intervention 22 avril 2012 1
4 juin 2007 à 13:01
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 !
0
Rejoignez-nous