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 :

destruction d'objets dans un vecteur


Sujet :

C++

  1. #1
    Membre averti Avatar de titouille
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    353
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 353
    Points : 356
    Points
    356
    Par défaut destruction d'objets dans un vecteur
    Bonjour !!!

    Voilà. Je récupère un pointeur sur un vecteur de "command", qui correspond à un vecteur de pointeurs sur des instances de classe "command".

    voici la redéfinition du tableau de pointeurs, ainsi que le proto de la méthode appelée, qui me retourne ce fameux pointeur sur un vecteur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    typedef vector< command* > v_commands; 
    v_commands* parseFragment( string xmlFragment );

    Chaque pointeur du vecteur pointe sur une instance de "command" qui a été créée avec l'opérateur new avant d'être insérée dans le tableau.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    v_commands* aCommands = new v_commands;
     
    for( ... )
    {
    command* cmd = new command();
     
    // ajout du pointeur de "cmd" dans le vecteur
    (*aCommands).push_back( cmd );
    }
    Je pars donc du principe que si j'ai utilisé "new", il faut donc que je fasse un "delete" pour éviter les fuites mémoires.

    Après le traitement de mon vecteur, j'aimerai donc faire un delete sur chaque élément, afin de libérer la mémoire allouée pour le processus.

    J'ai donc créé une méthode comme suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    void DesallocCommands( v_commands* cmds )
    	{
    	for( int i = (*cmds).size(); i > 0; i-- )
    		delete (*(*cmds).at(i));
     
    	(*cmds).clear();
    	}
    A laquelle je passe le pointeur sur mon vecteur.

    Je pensais ensuite pouvoir déréférencer tout d'abord le vecteur

    (*cmds)

    puis récupérer le pointeur à l'index i

    (*cmds).at(i)

    et enfin, déréférencer ce dernier

    (*(*cmds).at(i))

    pour appliquer un delete dessus, ce qui me semble logique, pour atteindre le réel élément en mémoire et non pas son pointeur ou autre chose... Mais non, ma console plante lamentablement...

    J'ai tenté plusieurs recherches sur le forum, j'ai lu dans la FAQ le chapitre sur les destructeurs, mais il doit me manquer un élément... C'est surement tout con, mais je n'arrive pas à trouver...

    Si quelqu'un détecte l'erreur, je lui en serai reconnaissant

    D'avance merci.

  2. #2
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    salut,

    ne serait-ce pas simplement[EDIT]ou[/EDIT]

    et pour le test de la boucle for je mettrai i>=0

  3. #3
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut Re: destruction d'objets dans un vecteur
    Citation Envoyé par titouille
    Je pars donc du principe que si j'ai utilisé "new", il faut donc que je fasse un "delete" pour éviter les fuites mémoires.
    Bon principe. Attention par contre, si tu dupliques un des pointeurs, il faut faire attention à ne pas effacer plusieurs fois l'objet (par exemple, avec un tel vector, impossible d'appeler correctement remove).
    Citation Envoyé par titouille
    Je pensais ensuite pouvoir déréférencer tout d'abord le vecteur
    C'est généralement assez rare de manipuler un pointeur sur un vecteur... Qu'est-ce qui justifie ce choix ici ?
    Citation Envoyé par titouille
    (*cmds)

    puis récupérer le pointeur à l'index i

    (*cmds).at(i)

    et enfin, déréférencer ce dernier
    Pourquoi ? Faire ça est équivalent à
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    int *pi = new int;
    delele *i;
    Ce qui n'est pas bon.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Membre averti Avatar de titouille
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    353
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 353
    Points : 356
    Points
    356
    Par défaut
    Hem...

    Tout d'abord, merci pour le >=, je me concentrais trop sur ce problème de destructeur...

    Ensuite, alors là, c'est très bizarre....

    Avant, j'avais essayé de faire delete (*cmd).at(i) comme tu le souligne, et je tombais sur une erreur du genre

    type 'class command' argument given to 'delete', expected pointer



    Je viens de retester, et cette fois, ça passe sans autre, alors que c'est ma première syntaxe qui me retourne cette erreur (*(*cmd).at(i)).

    La je ne comprend plus trop, mais ça ne résoud pas mon problème... le lamentable plantage est toujours présent dès le passage dans la boucle

  5. #5
    Membre averti Avatar de titouille
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    353
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 353
    Points : 356
    Points
    356
    Par défaut
    Merci JolyLoic pour tes explications...

    Je ne suis pas forcément sur de ce que je fais, mais voilà le principe :

    une classe de base virtuelle me permet d'étendre de nouvelles classes possédant une fonction "execute".
    Le but est de pouvoir instancier "dynamiquement" (avec une sorte de command factory) une classe et lui passer un vecteur de commandes ainsi qu'un index. L'index permet de récupérer la bonne commande, et de la traiter... Je passe le vecteur entier pour une bonne raison, c'est qu'une commande pourrait utiliser le résultat d'une commande exécutée précédement. Donc je dois à tout moment pouvoir récupérer n'importe quelle commande durant mes processus.

    Je pensais passer un pointeur sur un vecteur plutot qu'un vecteur directement car le vecteur passe par plusieurs classes/méthodes avant d'enfin arriver au processus ou il est réellement utilisé.
    Je pensais donc à un utiliser un pointeur pour alléger les éléments passés en paramètres, mais bon, vu que je débute, c'est peut-être une grosse erreur de débutant...


    Je pense par contre avoir compris ta dernière remarque. Tu démontre qu'on doit faire un delete sur un pointeur et non pas sur le réel contenu, c'est bien ça ??

    Mais c'est à ce moment que j'ai un peu de peine à comprendre le reste de la logique... supprimer un pointeur ne va pas supprimer le contenu en mémoire ?? Est-ce seulement le pointeur qui vient en mémoire et qui demande un delete, alors que le réel contenu sera supprimé tel une variable locale ?? Je commence à m'emméler les pinceaux...

  6. #6
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 534
    Points : 6 723
    Points
    6 723
    Par défaut
    c'est ton indice de vecteur qui est faux :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
       for( int i = (*cmds).size(); i > 0; i-- )
          delete (*(*cmds).at(i));
    lorsque le vecteur à n éléments les indices vont de 0 à n-1, pas de 1 à n
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  7. #7
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    delete s'applique sur un pointeur pour détruire la valeur que celui-ci pointe. Le pointeur en lui même n'est pas détruit par delete.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  8. #8
    jmv
    jmv est déconnecté
    Membre confirmé Avatar de jmv
    Profil pro
    Enseignant
    Inscrit en
    Mai 2004
    Messages
    395
    Détails du profil
    Informations personnelles :
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Mai 2004
    Messages : 395
    Points : 603
    Points
    603
    Par défaut
    Citation Envoyé par titouille
    La je ne comprend plus trop, mais ça ne résoud pas mon problème... le lamentable plantage est toujours présent dès le passage dans la boucle
    heu... oui il y a un 2eme bug dans ta boucle : dsl
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    for( int i = (*cmds).size()-1 ; i >= 0; i-- )
    //                         ^ici
    pourquoi pas faire simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(int i=0 ; i < cmds->size() ; i++)

  9. #9
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Peut-être qu'avec un code un peu moins alambiqué tu aurais moins de problème ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void DesallocCommands(v_commands& cmds)
    {
        for (v_commands::iterator i = cmds.begin(); i != cmds.end(); ++i)
            delete *i;
     
        cmds.clear();
    }
    Ou encore :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    struct Delete
    {
        template <typename T> void operator ()(const T* Ptr) const
        {
            delete Ptr;
        }
    };
     
    void DesallocCommands(v_commands& cmds)
    {
        std::for_each(cmds.begin(), cmds.end(), Delete());
     
        cmds.clear();
    }
    L'avantage c'est que le foncteur Delete peut être utilisé pour n'importe quel type stocké. Voir la FAQ C++ pour plus de détails sur les foncteurs.

  10. #10
    Membre averti Avatar de titouille
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    353
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 353
    Points : 356
    Points
    356
    Par défaut
    argh...


    z'auriez pas un trou de souris pour que je puisse allez y croupir

    Vraiment désolé d'avoir planté sur une erreur si basique...

    JolyLoic a dit :
    delete s'applique sur un pointeur pour détruire la valeur que celui-ci pointe. Le pointeur en lui même n'est pas détruit par delete.
    Ok, là ça me semble à nouveau logique.

    Tu as également parlé de "duplication"... J'ai un petit doute sur ce qu'est la duplication...

    Lorsque je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    command* cmd = new command();
    cmds.push_back( cmd );
     
    command* myCmd = cmds->at(i);
    Je ne fais pas une duplication mais une simple création de variable et affectation du contenu... ?? en fait, je récupère le pointeur sur mon élément, il n'y a pas de nouvelle variable enregistrée en mémoire, j'imagine...


    jmv a dit :
    pourquoi pas faire simplement

    for(int i=0 ; i < cmds->size() ; i++)
    Tu as tout à fait raison, et tu fais bien de me le rappeler. Je n'ai pas encore bien l'habitude de la syntaxe "->" pour les pointeurs.

    Merci à vous tous pour vos précieux conseils

  11. #11
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par titouille
    Tu as également parlé de "duplication"... J'ai un petit doute sur ce qu'est la duplication...

    Lorsque je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    command* cmd = new command();
    cmds.push_back( cmd );
     
    command* myCmd = cmds->at(i);
    Je ne fais pas une duplication mais une simple création de variable et affectation du contenu... ?? en fait, je récupère le pointeur sur mon élément, il n'y a pas de nouvelle variable enregistrée en mémoire, j'imagine...
    Tu as là 2 duplications (=copies) du pointeur : dans push_back, tu copies le pointeur, et dans at, tu le copies aussi. Ce qui n'est pas gênant, tant que tu ne t'amuses pas à faire par la suite un delete cmd; ou un delete myCmd;. En gros, si tu décides d'effacer à la destruction du vecteur ce qu'il y a dedans, c'est lui qui est propriétaire de ces données. Si un autre endroit du code essaye de les effacer, c'est du "vol" de données caractérisé, qui risque de poser problème.

    Mon avertissement était dû au fait que parmis les différents algorithmes qu'on peut appliquer sur un vector, certains s'amusaient à enlever des données sans te prévenir, et donc sans te laisser l'occasion d'effacer ce qui est pointé. Un alog comme std::sort duplique les pointeurs à tour de bras, mais sans problème, puisqu'à la fin, on se retrouve avec les mêmes qu'au début, mais dans un autre sens. std::remove duplique aussi dans tous les sens, mais certains poienteurs n'existent plus, d'autres existent en double. On a donc du mal à utiliser ces algorithmes avec des vecteurs de pointeurs.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  12. #12
    Membre averti Avatar de titouille
    Profil pro
    Inscrit en
    Juin 2005
    Messages
    353
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Juin 2005
    Messages : 353
    Points : 356
    Points
    356
    Par défaut
    Ok JolyLoic, je crois que je comprend le principe. On décide une fois pour toute à quel endroit on décide de faire les delete sur des pointeurs, et on ne les delete qu'une seule fois. Ce qui implique également de savoir qu'après le delete, on ne va pas pouvoir réutiliser les pointeurs dupliqués.

    Je ne suis pas encore vraiment à l'aise avec pointeurs et références... Par exemple, dans l'exemple "template" de Loulou (je te remercie Loulou, les foncteurs sont vraiment très intéressant à utiliser), c'est une référence qui est passée à la méthode, non pas un pointeur... Pour ma part, j'ai repassé un pointeur, mais est-ce que celà peut influer sur le reste ??

    Je me suis par exemple rendu compte que j'ai beau instancier mes "commandes" avec new, le destructeur est tout de même appelé implicitement...
    Donc si j'applique ma fonction DesallocCommands, je me retrouve avec 2 passages dans les destructeurs de mes objets...

    Parallèlement, dans mes instances de commandes, j'instancie des objets de classe "parameter", également en passant par l'opérateur new. Cette fois, le destructeur n'est pas appelé implicitement, et je dois bien passer par delete pour les supprimer...

    Je pense donc implémenter l'appel au Template également dans le destructeur de "command", pour supprimer les paramètres stocké dans l'instance (dans un vecteur, encore une fois...)


    En tout cas, merci à vous tous de contribuer et de partager vos connaissances.

  13. #13
    fd
    fd est déconnecté
    Membre habitué
    Profil pro
    Inscrit en
    Mai 2002
    Messages
    131
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2002
    Messages : 131
    Points : 162
    Points
    162
    Par défaut
    le plus simple dans ce cas serait d'utiliser un shared_ptr (de boost) qui se chargera de la désallocation

Discussions similaires

  1. Pointeur vers objet dans un vecteur
    Par julieng31 dans le forum C++
    Réponses: 3
    Dernier message: 27/09/2013, 09h29
  2. Récupération d'un objet dans un vecteur
    Par Madoka dans le forum Langage
    Réponses: 8
    Dernier message: 10/03/2009, 21h59
  3. Réponses: 6
    Dernier message: 14/11/2007, 15h51
  4. Tri d'objets dans un vecteur
    Par Jahjouh dans le forum C++
    Réponses: 5
    Dernier message: 26/01/2006, 18h23
  5. Mettre un objet utilisant COM dans un vecteur
    Par 0xYg3n3 dans le forum MFC
    Réponses: 7
    Dernier message: 18/04/2005, 15h50

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