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 !
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.
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 ?
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...
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...
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...
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..
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.
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 !
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 !