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 :

Appel destructeur qui ne se fait pas


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 34
    Points : 31
    Points
    31
    Par défaut Appel destructeur qui ne se fait pas
    Bonjour tout le monde,

    j'optimise actuellement un projet que j'ai a faire, et donc je vérifie le nombre d'appels de destructeur effectué (grace à des variables globales: je sais que ce n'est pas bien mais c'est juste pour le test) pendant le programme, il s'agit d'une liste doublement chainée avec un mSuivant et mPrecedent (vers des classes type umh.

    Donc je vous présente mon destructeur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    umh::~umh(void){
     
                    delete mSuivant;
                    delete mPrecedent; 
                    CD++;
                    }
    Un parcours d'une liste :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void Materiau::Affiche(void){
         cout<<"Affichage"<<endl;
         umh *test;
         Parametre Param;
         test=new umh;
         test=*mTete;
         while(test){
                     test->AfficheAdresse();     
                     test=test->Suivant();
                     }
             delete test;
                    }
    et enfin ma fonction qui affiche le nombre d'appel de constructeurs et destructeurs:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void umh::Verification(void){
     
         cout<<"Nombre d'appels de constructeur:    "<<CC<<endl;
         cout<<"Nombre d'appels de destructeur:     "<<CD<<endl;
         }

    Bon rien de compliqué me direz vous, cependant à la sortie "de Affiche" la variable CD vaut toujours 0...Comment se fait se?

    Une autre question: mon destructeur vous parrait t-il correct?

    MMerci pour vos réponses!

  2. #2
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Bonsoir,
    Voila le problème:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    test=new umh; //Ici on alloue
    test=*mTete; //Ici on perd le pointeur qui vient d'être alloué. C'est une fuite mémoire.
    while(test) //On fait des chose tant que test != NULL
    {
      test->AfficheAdresse();     
      test=test->Suivant();
    }
    delete test;//Donc ici test est forcement null
    Il n'y as aucune désalocation dans ce code.

    Une autre question: mon destructeur vous parrait t-il correct?
    Si "umh" est un nœud de ta liste, et qu'il delete a la fois le suivant et le précédent, il y auras forcement des nœuds desaloué deux fois.

  3. #3
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Et je rajouterais, pour le destructeur, vu qu'il n'y a pas mise à null de pointeurs, tu vas faire des delete multiples, et le comportement est indéfini.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    mSuivant->mPrecedent = null;
    mPrecedant->mSuivant = null;
    delete mPrecedant;
    delete mSuivant;

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 34
    Points : 31
    Points
    31
    Par défaut
    Salut Nogane,Salut Julien Du Sud,

    en effet la ligne new umh ne sert à rien, je pense que si je la supprime cela va éviter une fuite mémoire...
    cependant, a la sortie de la fonction affiche, il faut bien "liberer" test non puisqu'il a été appelé avec new?
    Dans ce cas le delete devrait faire un appel destructeur et m'incrémenter ma variable de 1 ce qui n'est pas le cas...

  5. #5
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    un new est à coupler avec un delete, mais si tu ne fais pas de new, il n'y a pas de delete à faire.

    Un pointeur n'est pas forcément une donnée allouée dynamiquement. Et il n'y a pas de delete à faire pour les données allouées statiquement, étant donné que celles-ci sont détruites lorsqu'elle sort de sa portée.

    Tu devrais voir la FAQ et quelques tutoriels...

  6. #6
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 34
    Points : 31
    Points
    31
    Par défaut
    Je pense que je viens de tilter...
    En fait quand j'ai un pointeur p=NULL, faire delete p ca sert à rien? Moi je pensais que le fait que le pointeur pointait vers 0 et que la mémoire était désalouée ne voulait pas dire la même chose...Peut être que tout est entrain de s'embrouiller dans ma tête aussi

  7. #7
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Faire un delete sur un pointeur à NULL ne fait rien, et justement c'est ça qu'est bien. (par rapport au code que t'a montré juliendusud pour éviter deux désallocations).

    Sinon l'exercice c'est d'implémenter la liste? Parce que si c'est pour être utilisé t'as std::list qui est une liste doublement chainée .
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Octobre 2008
    Messages
    34
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2008
    Messages : 34
    Points : 31
    Points
    31
    Par défaut
    merci goten,

    mais j'aime bien réinventer la roue à chaque fois (bon je sais des fois elle est carrée mais bon...), la preuve en est que c'est utili, c'est que je bloque sur des notions assez simples (pour des programmes quand même assez complexes dans leur ensemble)

    En tout cas merci pour votre aide à tous

  9. #9
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 33
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Que tu réinventes la roue pour un exercice pourquoi pas... après si tu as besoin dans un programme d'une liste chainée alors utilise la STL. Tu feras pas mieux. Ou même si tu as le niveau de faire équivalent ta solution n'auras jamais la maturité qu'a la STL.
    "Hardcoded types are to generic code what magic constants are to regular code." --A. Alexandrescu

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

    Informations professionnelles :
    Activité : aucun

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

    Ceci dit, il y a un point qui n'a absolument pas été abordé et ca me chagrine énormément: celui de la délégation des tâches.

    En effet, dans l'exemple présenter, on trouve quatre responsabilités différentes, qui devraient toutes être "traduites" sous la forme d'une classe (ou d'un type) particulier.

    Il y a :
    • le type Materiaux, qui doit disposer d'une liste d'objets et pouvoir
      • ajouter des objet à la liste
      • retirer des objets de la liste
      • parcourir la liste
      • éventuellement vider explicitement la liste
    • un type "liste d'objets" (manquant dans le code) qui doit gérer les différents éléments en veillant à ce que ca reste cohérent, à savoir:
      • ajouter un (ou des) élément(s) (en début de chaine, à la fin, voir entre deux éléments)
      • retirer un ou des élément(s)
      • accéder au premier élément
      • accéder au dernier élément
      • supprimer tous les éléments
      • (idéalement) pouvoir indiquer si elle est vide
      • (idéalement) pouvoir indiquer le nombre d'éléments qu'elle contient
    • le type mhu représent un élément de la liste et qui doit donc:
      • permettre d'accéder à l'élément qui le précède
      • permettre d'accéder à l'élément qui le suit
      • permettre de récupérer l'objet de type particulier maintenu par l'élélemnt
    • le type de donnée particulier (non représenté ici) qui représente, finalement, les données que tu veux gérer sous forme de liste.
    Je passe sur le type de données que tu veux gérer sous forme de liste, simplement, pour que l'exemple soit cohérent, je l'appellerai Donnee

    L'élément de la liste (que je vais renommer en Element, car c'est plus parlant, mais qui correspond à mhu ) se présentera sous une forme proche de
    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
    class Element
    {
        public:
            Element(Donnee const & d):d_(d),prev_(0),next_(0){}
            /* le destructeur est trivial, on peut garder celui implémenté
             * par défaut
             */
            /* Par contre, je verrais bien cette classe être non copiable et
             * non assignable, mais éventuellement clonable (permettre
             * d'obtenir un nouvel élément manipulant un objet de type Donnee
             * identique, mais qui n'est pas relié  aux mêmes éléments précédents
             * et suivants )
             */
             Element* clone() const 
             {
                 Element* ret= new Element(d_);
                 return ret;
             }
             /* l'acces à l'élément précédent */
             Element* previous(){return prev_;}
             /* l'acces à l'élément suivant */
             Element* next() {return next_;}
             /* l'acces à la donnée */
             Donnee const & data() const{return d_;}
        private:
             /* empêchons la copie et l'affectation en déclarant le
              * constructeur par copie et  l'opérateur d'affectation privé et
              * en ne les définissant pas
              */
             Element(Element const &);
             Element&  operator=(Element &);
             /*  la relation vers l'élément précédent */
             Element* prev_;
             /* la relation vers l'élément suivant */
             Element* next_;
             /* et la donée manipulée */
             Data  d_;
             /* par facilité, laissons libre accès à tout cela  au départ de
              * la liste
              */
             friend class Liste;
    };
    La liste prendrait une forme proche de
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    class Liste
    {
        public:
            List():first_(0),last_(0){}
            /* le destructeur veille à détruire tous les éléments qu'elle 
             * contient
             */
            ~List()
            {
                 clear();
            }
            /* la liste est copiable
             */
            Liste(Liste const & rhs):first_(0),last_(0)
            {
                 Element*  temp=rhs.first_;
                 while(temp)
                 {
                      push_back(temp->d_);
                      temp=temp->next_;
                 }
            }
            /* la liste est swappable (on peut intervertir le contenu de deux
             * listes)
             */
            void swap(Liste  & rhs)
            {
                std::swap(first_,rhs.first_);
                std::swap(last_,rhs.last_);
            }
            /* et elle est assignable (on utilise l'idiome copy and swap) */
            Liste& operator=(Liste const& rhs)
            {
                Liste temp(rhs);
                swap(rhs);
                return this;
            }
            /* reste à créer les fonctions "qui vont bien" */
            void push_back(Donnee const & d)
            {
                Element* toadd=new Element(d);
                if(first_==0)
                    first_=toadd;
                if(last_!=0)
                    last_->next_=toadd;
                 toadd->prev_=last_;
                 last_=toadd;
            }
            void push_front(Donnee const& d)
            {
                Element* toadd=new Element(d);
                if(first_!=0)
                    first_->prev_=toadd;
                if(last_==0)
                    last_=toadd;
                 toadd->next=first_;
                 first_=toadd;
            }
            void insert(Element* prev,Donnee const& d)
            {
                ASSERT(prev!=0);
                Element* toadd=new Element(d);
                toadd->prev_=prev;
                toadd->next_=prev->next_;
                if(prev->next_!=0)
                    prev->next_->prev_=toadd;
                prev->next_=toadd;
                if(prev==last_)
                    last_=toadd;
            }
            void  erase(Element* torem)
            {
                ASSERT(torem!=0);
                if(torem->prev_!=0)
                    torem->prev_->next_=torem->next_;
                if(torem->next_!=0)
                     torem->next_->prev_=torem->prev_;
                if(torem==first_)
                    first_=torem->next_;
                if(torem==last_)
                    last_=torem->prev_;
                delete torem;
            }
            void clear()
            {
                while(first_)
                {
                    Element* temp=first_->next_;
                    delete first_;
                    first_= temp;
                }
            }
            Element* first(){ return first_; }
            Element* last(){ return last_; }
            bool empty() const {return first_==0;}
            size_t size() const
            {
                 size_t ret=0;
                 Element* temp=first_;
                 while(temp)
                 {
                     ++ret;
                     temp=temp->next_;
                 }
                 return ret;
            }
    };
    enfin, la classe Matériaux dispose d'un membre de type Liste, et peut la manipuler à son aise, sous une forme proche de
    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
    class Materiaux
    {
        public:
             /* sauf spécification contraire,  constructeurs (par défaut et par
              * copie), destructeur et opérateur d'affectation sont triviaux
              * laissons le compilateur s'en charger ;)
              */ 
     
             /* les fonctions de Matériaux, dont */
             void Affiche() const
             {
                 Element* temp=liste_->first();
                 while(temp)
                 {
                     temp->data().afficheAdresse();
                     temp=temp->next();
                 }
             }
             /* nous aurons sans  doute une fonction d'ajout d'information,
              * prenant la forme de
              */
             void addInfoLast(Donnee const & d)
             {
                 liste_.push_back(d);
             }
             /* ou d'autres... */
        private:
            Liste liste_;
    };
    [EDIT]je disais que Element pouvait éventuellement être cloné, mais, sur base du code que je te fournis ici, il n'y a pas de raison incitant à prévoir un tel comportement
    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. [Mail] Envoi d'e-mail qui ne se fait pas
    Par sam01 dans le forum Langage
    Réponses: 3
    Dernier message: 26/07/2007, 10h41
  2. rsync : sauvegarde incrementale qui ne se fait pas
    Par nixonne dans le forum Shell et commandes GNU
    Réponses: 1
    Dernier message: 22/07/2007, 12h11
  3. [Tableaux] création de tableau qui ne se fait pas
    Par mussara dans le forum Langage
    Réponses: 2
    Dernier message: 01/11/2006, 21h44
  4. Test qui ne se fait pas
    Par GLDavid dans le forum Linux
    Réponses: 12
    Dernier message: 07/03/2006, 14h57
  5. Pb de selection qui ne se fait pas
    Par Stef.proxi dans le forum Langage SQL
    Réponses: 4
    Dernier message: 06/08/2004, 10h54

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