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 :

Destructeur Liste d'objet B dans une classe A


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut Destructeur Liste d'objet B dans une classe A
    Bonjour,

    Je précise avant de démarrer: j'ai vraiment du mal avec le concept de programmation, et surtout surtout je n'ai pas l'esprit "objet". Mon message sera donc sûrement très élémentaire...

    En gros, voilà ce que j'ai:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    //Constructeur d'un objet de classe A
    A::A(string iD) {
    _iD = iD;
    _liste = list<B>();
     
    //Destructeur
    A::~A(){
     
    }
    Comme vous le voyez, dans mon constructeur d'objet A, j'ai une liste d'objets B (qui n'est pas passée en paramètre du constructeur). J'aimerais donc savoir, comment détruire cette liste? Dois-je faire appel au destructeur de l'objet B? Et comment? En parcourant la liste?

    Je pensais naïvement qu'un simple delete_liste; fonctionnerait, mais ce n'est pas le cas


    Merci d'avance pour vos réponses!!

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    On utilise delete uniquement sur des pointeurs qui pointent sur des objets alloués dans le tas par un new.
    (les new/delete et new[]/delete[] vont toujours par paire)

    Pour tout le reste, le C++ est entièrement fondé sur un principe de portée, (ou bloc), symbolisé par des {}
    Un objet appartient toujours à une portée, et quand on sort de la portée son destructeur est automatiquement appelé.
    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
    void f()
    { // debut portée de f
     
     
    } // fin portée de f
     
    int main()
    { // début portée main
     
       { // debut portée anonyme
       //...
     
       } // fin portée anonyme
     
    } // fin portée du main
    Les objets alloués dans le tas par new sont une exception. Ils ne sont pas détruit automatiquement quand on sort de la portée dans laquelle ils ont été alloué. Il faut donc bien faire attention à conserver un pointeur sur eux, ou bien à les détruire avec un delete avant de quitter la portée, sinon ils resteront coincés en mémoire, inaccessibles, jusqu'à la fin du programme.

    En résumé :
    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
     
    struct B
    {
    };
     
    struct S
    {
    std::list<B> l;
    };
     
    int main()
    {
       {
          std::vector<int> v;
       } // on sort de la portée, le destructeur de v est appelé
     
       {
          S;
       }  // on sort de la portée, le destructeur de S est appelé
         // ainsi que le destructeur de l et de tous les B
     
       {  
           int* ptr = new int;
          *ptr = 5;
      } // fuite mémoire ! Le pointeur est détruit mais pas l'objet pointé.
       // l'entier restera en mémoire, inaccessible, jusqu'à la fin du main.
     
      {
         int* ptr = new int;
        *ptr = 5;
        delete ptr;
      } // ok, l'objet pointé a bien été détruit avant de sortir de la portée
    }
    Donc pas besoin de détruire explicitement _liste, car en sortant de la portée son destructeur est automatiquement appelé ainsi que celui de _liste et de chacun des B.


    Par contre, si _liste avait été un std::list<B>*, alloué sur le tas par un new, ou bien un std::list<B*>, avec chaque objet B alloué dans le tas par un new, alors en effet il aurait fallu un delete dans le destructeur, soit sur _liste lui-même, soit sur chacun des pointeurs sur B de la liste.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Salut, et bienvenue sur le forum
    Citation Envoyé par iori11 Voir le message
    Bonjour,

    Je précise avant de démarrer: j'ai vraiment du mal avec le concept de programmation, et surtout surtout je n'ai pas l'esprit "objet". Mon message sera donc sûrement très élémentaire...

    En gros, voilà ce que j'ai:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
     
    //Constructeur d'un objet de classe A
    A::A(string iD) {
    _iD = iD;
    _liste = list<B>();
     
    //Destructeur
    A::~A(){
     
    }
    Comme vous le voyez, dans mon constructeur d'objet A, j'ai une liste d'objets B (qui n'est pas passée en paramètre du constructeur). J'aimerais donc savoir, comment détruire cette liste? Dois-je faire appel au destructeur de l'objet B? Et comment? En parcourant la liste?

    Je pensais naïvement qu'un simple delete_liste; fonctionnerait, mais ce n'est pas le cas


    Merci d'avance pour vos réponses!!
    Ce qui est bien avec la std::list (tout comme avec l'ensemble des container de la STL, d'ailleurs), c'est qu'elle respecte le RAII (et, dans le cas qui nous intéresse son contraire )

    En effet, lorsque la liste est détruite, le destructeur de tous les éléments qu'elle contient est automatiquement appelé (du moins, tant que tu n'utilise pas la gestion dynamique de la mémoire).

    De plus, le destructeur de la liste (comme de tous les membres d'une classe d'ailleurs) est automatiquement appelé lorsque l'instance de cette classe est détruite (du moins, tant qu'il n'y a pas une notion de gestion dynamique de la mémoire qui entre en ligne de compte pour l'un des membres)

    Dans l'exemple que tu donne, il ne faut donc pas t'en faire: tous les B contenus dans ta std::list seront bel et bien détruits lorsque l'instance de A sera détruite

    Par contre, si tu souhaite vider la liste en question, la fonction à appeler est clear
    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

  4. #4
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Merci beaucoup pour ces réponses qui m'éclairent énormément!!

    Donc, ok pour le list<B>. Et si j'avais un list<B*>, je devrais procéder comment pour une destruction efficace? Comme ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for (std::list<B*>::iterator b = _liste.begin(); b != _liste.end(); b++){
    		delete (*b);
    	}
    Ou tout simplement comme ça:


  5. #5
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Solution 1 car la solution 2 vide la liste sans rien désallouer.
    Cela vient de la différence entre pointeur et éléments pointés.


    La solution 1 va détruire les éléments pointés alors que la liste 2 va juste détruire les pointeurs.


    Ta solution 1 peut être ré-écrite avec for_each et un foncteur qui va détruire les éléments
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Tu devrais utiliser la première solution si tes B* ont été créés dynamiquement uniquement. (avec new)

    En effet, il est possible (bien que peu conseillé) d'envisager que ta liste de B* soit remplie avec les adresses de B, créés de manière tout à fait "classique" (comprend: sans recourir à new) qui existent par ailleurs, et dans ce cas, il n'y a pas lieu d'invoquer delete sur tes pointeurs

    Mais, comme je n'ai dit, ce n'est pas conseillé car il faut veiller à ce que les pointeurs ne soient pas invalidés pour une raison ou une autre, sous peine d'avoir des problèmes sans noms
    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
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par Davidbrcz Voir le message
    Ta solution 1 peut être ré-écrite avec for_each et un foncteur qui va détruire les éléments
    C'est-à-dire? Quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for_each(_liste.begin(),_liste.end(),supprimer); 
    supprimer(){delete this;}
    Bon ce n'est pas gagné, je récupère un projet avec des map de map dont les valeurs sont des pointeurs, des listes à tout va, et des destructeurs vides jamais appelés... Je n'ai jamais fait de C++ (je veux dire mener un projet seule de bout en bout) et je ne sais pas comment je vais m'en sortir

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par iori11 Voir le message
    Bon ce n'est pas gagné, je récupère un projet avec des map de map dont les valeurs sont des pointeurs,
    Cela, ce sera potentiellement le problème le plus important...

    Mais je présumes que tes map sont placées dans des structures.

    Il faut donc vérifier si, d'une manière ou d'une autre, le destructeur de ces structures invoque bel et bien delete sur le pointeur

    des listes à tout va, et des destructeurs vides jamais appelés...
    Le destructeur est systématiquement appelé sur les variables qui n'ont pas été allouées dynamiquement (avec new) lorsque l'on quitte la portée dans laquelle elles ont été déclarées (ou lorsque l'instance de la classe dans laquelle la variable est un membre est détruite)

    La présence de destructeurs vide est souvent du au besoin de polymoprhisme, qui implique la définition d'une destructeur non trivial car, tout simplement, virtuel

    Si la classe en question ne manipule pas des pointeurs sur des objet alloués dynamiquement, un tel destructeur a toutes les raisons de rester vide (car le destructeur des membres qui ne sont pas alloués dynamiquement se fait de manière automatique )
    Je n'ai jamais fait de C++ (je veux dire mener un projet seule de bout en bout) et je ne sais pas comment je vais m'en sortir
    En gardant ton calme, en respirant un bon coup et en appliquant la pensée positive (Il n'y a pas de problème, il n'existe que des solutions... même si je dois encore les trouver )

    Si tu "n'entrave que dalle" au C++, l'idéal est de commencer par un cours d'initiation ou des tutoriaux (tu en trouvera ==>ici<==)

    La pensée positive devrait t'inciter à espérer qu'il existe des documents de conceptions, des spécifications et autres documents intéressant pour savoir comment s'articule le projet...

    Même si tu risque d'être déçu(e ) de ne rien trouver, tu ne risques pas grand chose à tenter de remettre la main dessus

    Si tu les trouve, tu pourras déjà partir de leur étude afin de te familiariser avec le projet

    Si tu ne les trouves pas, il te restera le recours éventuel à certains outils comme doxygen qui te permettront, à défaut d'avoir des document de conception, de te faire une idée plus ou moins raisonnable du projet

    Pour le reste, avec un peu de bon sens et d'opiniâtreté, le tout éventuellement soutenu par l'aide que tu pourra obtenir ici, cela devrait pouvoir aller (même si je n'irai pas jusqu'à prétendre que ce sera facile )
    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

  9. #9
    Membre à l'essai
    Inscrit en
    Juin 2008
    Messages
    18
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 18
    Points : 10
    Points
    10
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Cela, ce sera potentiellement le problème le plus important...

    Mais je présumes que tes map sont placées dans des structures.
    Que nenni!!

    En gardant ton calme, en respirant un bon coup et en appliquant la pensée positive (Il n'y a pas de problème, il n'existe que des solutions... même si je dois encore les trouver )
    Oui, rester positive... Effectivement, le forum m'aide beaucoup! Seule face à tout ça c'est un peu difficile...

    La pensée positive devrait t'inciter à espérer qu'il existe des documents de conceptions, des spécifications et autres documents intéressant pour savoir comment s'articule le projet...

    Je vous tiens au courant, je suis loin d'être à ma dernière question!

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    Citation Envoyé par iori11 Voir le message
    Que nenni!!
    Alors, c'est à toi de veiller à ce que la mémoire allouées aux pointeurs soient correctement libérée avant de "perdre la trace" à la map dans laquelle ils sont maintenus (ou de tout autre conteneur qui pourrait les contenir)...

    Ceci dit, il peut sembler opportun de citer:
    • les pointeurs intelligents, qu'il est souvent préférable d'utiliser plutôt que les pointeurs "nu"
    • les "ptr_containers" de la bibliothèque boost qui s'assurent que la mémoire allouée aux pointeurs qu'ils contiennent est effectivement correctement libérée lorsque le conteneur est détruit

    Oui, rester positive... Effectivement, le forum m'aide beaucoup! Seule face à tout ça c'est un peu difficile...
    Qui a dit que tu était seule
    Je vous tiens au courant, je suis loin d'être à ma dernière question!
    N'hésite surtout pas

    Veille simplement à créer des discussions séparées pour les différents problèmes que tu peux rencontrer...

    Cela facilitera un travail de recherches ultérieures (pour toi ou pour toute autre personne se posant une question similaire)
    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. Utilisation des objets form dans une classe
    Par quikjean dans le forum Visual Studio
    Réponses: 0
    Dernier message: 27/07/2009, 22h31
  2. [POO] Sérialiser un objet PDO dans une classe
    Par __fabrice dans le forum Langage
    Réponses: 9
    Dernier message: 15/09/2008, 22h30
  3. Réponses: 2
    Dernier message: 21/05/2007, 20h43
  4. Réponses: 1
    Dernier message: 13/09/2006, 11h50
  5. Créer une liste d'objets statiques dans une classe
    Par crossbowman dans le forum C++
    Réponses: 3
    Dernier message: 13/03/2006, 09h11

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