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 :

Comprendre le comportement d’un Itérateur dans une liste


Sujet :

C++

  1. #1
    Nouveau membre du Club
    Inscrit en
    Juillet 2011
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2011
    Messages : 63
    Points : 36
    Points
    36
    Par défaut Comprendre le comportement d’un Itérateur dans une liste
    Salut à tous,
    J’ai une principale List de pointeur à objets qui est la liste principale.
    A chaque fois un objet est injecté dans cette liste je dois chercher dans une liste secondaire, de pointeur à objets,
    et suivant les attributs de l’objet injecté et suivant son type il est soit supprimé soit déplacé dans la deuxième List.
    Voici une version simplifié de mon code :

    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
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
     
     
    list<RequestMsg*>::iterator iter;
     
        for (iter = WBRequests.begin(); iter != WBRequests.end() ; ) {
     
        if (!ServedRequests.empty()){
     
        list<RequestMsg*>::iterator iter2;
     
        for (iter2 = ServedRequests.begin(); iter2 != ServedRequests.end(); ) {
     
     
        if (  condition sure les attributs de l'objet )
     
     
        {
        break;
     
        }
        }
     
        if (iter2 != ServedRequests.end()) // si l'objet est trouvé  
        {
     
        delete *iter2;   // supprimer l'iltérateur
        iter2 = ServedRequests.erase(iter2);
     
        }
     
        else {
     
       opp_error("ERROR   ");
     
        }
     
        list<RequestMsg*>::iterator iter4;
     
        for (iter4 = ServedRequests.begin(); iter4 != ServedRequests.end(); iter4++  ) {
     
     
        if (  condition sure les attributs  de l'objet )
     
        {
        break;
     
        }
     
      }
     
        if (  iter4 != ServedRequests.end()) // objet trouvé
        {
     
            (*iter4)->setIsPSok(true); // modifier un des attributs 
        isPShere= true;
     
         //   iter4++;  //incrémentez ou supprimez ?
     
     
        }
     
        else {
     
     
        delete *iter;  // plus besoin de l'objet 
        iter = WBRequests.erase(iter);
     
        iter4++;  //incrémenté ou supprimé ?
     
        isPShere= false;
     
        }
     
        if (isPShere){ 
     
     
                        list<RequestMsg*>::iterator iter5;
     
        for (iter5 = ServedRequests.begin(); iter5 != ServedRequests.end(); iter5++  ) {
     
        if (  condition sure les attribues de l'objet) // erreur: cette condition n'est jamais franchi  
     
                     {
     
                     break;
     
                     }
     
                     }
     
                      if (iterSer5 != ServedRequests.end())
                               {
     
                         delete *iterSer5;
     
                       //  iterSer5 = ServedRequests.erase(iterSer5);
                         iterSer5++;
                         delete *iter;
     
                         iter  = WBRequests.erase(iter );
     
                         isPShere= false;
     
                                 }
     
                             else {
                                          delete *iter5;
                     //   iter5= ServedRequests.erase(iter5);
                                          iter5++;
                                 delete *iter;
                                  iter  = WBRequests.erase(iter );
     
                                 isPShere= false;
     
                              }
                             }
                       }
                   }
    D'après la documentation de OMNET++ l'erreur que je reçois est

    ( invalid pointer access, the object the pointer is pointing to is deleted.) Ligne 81 .

    Ma question est c'est quoi la différence entre delete *iter et iter = WBRequests.erase(iter ) ?

    Pour le moment j'utilise les 2 en même temps quand j'ai plus besoin de l'objet, je le supprime et l’incrémentation se fait automatiquement.

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 261
    Points : 12 476
    Points
    12 476
    Par défaut
    "delete *iter" fout un bordel monstre dans la list et erase est plus flexible, s'intègre bien mieux avec les autres briques de la STL, mais surtout ne massacre pas les container STL.
    Donc vous oubliez, et très très vite, ce delete.

    Dans un code C++ bien écrit et moderne, il n'y a aucun delete.

    Votre code est très difficile à suivre malgré la simplicité des choses à faire. Je pense que vous devriez faire une petite séance de révision de la STL, et des algorithmes en particulier.

  3. #3
    Nouveau membre du Club
    Inscrit en
    Juillet 2011
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2011
    Messages : 63
    Points : 36
    Points
    36
    Par défaut
    Merci bacelar,

    Tous ce que je fais est de chercher un objet dans la seconde liste dont l'attribut satisfait certaine conditions. J'utilise une simple recherche comme dans ce code

    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
     
        list<RequestMsg*>::iterator iter2;
     
        for (iter2 = ServedRequests.begin(); iter2 != ServedRequests.end(); ) {
     
       if (  condition sure les attributs de l'objet )
     
         {
                   break;
     
        }
     
       }
     
        if (iter2 != ServedRequests.end()) // si l'objet est trouvé  
        {
     
     // modifiez  l'attribut
     
        }
     
        else {
     
     
               }
    je sais pas s' il y'a d' autre algorithme qui peuvent chercher dans une liste suivant les attributs des objets.

  4. #4
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 136
    Points : 33 095
    Points
    33 095
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par bacelar Voir le message
    "delete *iter" fout un bordel monstre dans la list et erase est plus flexible, s'intègre bien mieux avec les autres briques de la STL, mais surtout ne massacre pas les container STL.
    Donc vous oubliez, et très très vite, ce delete.
    Le delete libère la mémoire de l'objet pointé par l'itérateur, pas de l'itérateur ... *iter2 est un RequestMsg*
    Si ta liste est construite par des new, le delete est bon, sauf à vouloir faire des fuites mémoire.

    Je comprends pas quel est le problème ? Y'a un crash ? Une erreur ?

  5. #5
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 261
    Points : 12 476
    Points
    12 476
    Par défaut
    std::find_if
    http://www.cplusplus.com/reference/algorithm/find_if/

    Et oubliez les pointeurs nus donc les deletes => pointeurs intelligents.

  6. #6
    Nouveau membre du Club
    Inscrit en
    Juillet 2011
    Messages
    63
    Détails du profil
    Informations forums :
    Inscription : Juillet 2011
    Messages : 63
    Points : 36
    Points
    36
    Par défaut
    Citation Envoyé par Bousk Voir le message
    Je comprends pas quel est le problème ? Y'a un crash ? Une erreur ?
    Merci Bousk,
    l'erreur est causée par un invalid pointer access

  7. #7
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 197
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 197
    Points : 17 169
    Points
    17 169
    Par défaut
    invalid pointer access = tu as un pointeur qui traine.
    Ce pointeur pointe sur de la mémoire dés/in-allouée, mais tu le déréference quand même.

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 136
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 136
    Points : 33 095
    Points
    33 095
    Billets dans le blog
    4
    Par défaut
    un debugger t'indiquera très vite la ligne à problème

  9. #9
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 261
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 261
    Points : 12 476
    Points
    12 476
    Par défaut
    pointeurs intelligents => pas de delete => pas de " mémoire dés/in-allouée" => pas d'emmerdes.

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

    Informations professionnelles :
    Activité : aucun

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

    Reprenons depuis le début : qu'est ce qu'un itérateur

    Un iterateur, c'est simplement un concept qui nous permet de remplir l'un des trois besoins essentiels rencontrés lorsqu'on désire manipuler des collections d'objets/ de valeurs à savoir être en mesure d'itérer sur l'ensemble des éléments que la collection contient dans un ordre "logique".

    A ce titre, un itérateur doit fournir deux services essentiels :
    • permettre d'accéder à un itérateur sur l'élément suivant dans l'ordre logique d'itération et
    • permettre d'accéder à l'élément proprement dit

    Le premier service est fournit au travers de l'opérateur ++ et le second est fournit au travers des opérateur * et ->.

    Chaque collection fournit en outre différentes fonctions qui renvoient un itérateur, comme begin() et end() ou qui utilisent la notion d'itérateur afin de rendre les services que l'on attend d'eux (insert, erase, ...)

    Dans le cas présent, tu utilises une collection de pointeurs sur des objets. La première question est : faut-il réellement utiliser des pointeurs Ne pourrait-on pas se contenter de stocker ces objets par valeur Je n'ai pas les informations nécessaires pour apporter cette réponse, mais elle dépend (la réponse) de la sémantique de ta classe RequestMsg. S'il s'agit d'une classe ayant sémantique d'entité, cela se justifie par le fait que les classes ayant sémantique d'entité ne peuvent être ni copiées ni assignées. Si elle a sémantique de valeur, il n'y a aucune raison de recourir à l'allocation dynamique, et le maintient dans ta collection s'avérera beaucoup moins "casse-gueule".

    Par contre, si ta classe RequestMsg a sémantique d'entité, il est important de veiller à ce que la mémoire allouée aux différentes instances de cette classe soit libérée correctement et surtout au bon moment. Or, il est particulièrement difficile de gérer a la main le moment où cette libération survient, surtout lorsque tu dois transférer des pointeurs entre différentes collections.

    Comme baclear l'a déjà indiqué à plus d'une occasion dans cette discussion, l'idéal est donc de manipuler des pointeurs intelligents : std::unique_ptr ou std::shared_ptr si tu dispose d'un compilateur récent (supportant la norme C++11 ou postérieure), boost::unique_ptr ou boost::shared_ptr (si impossible d'utiliser C++11), implémentation personnalisée de ces concepts par une bibliothèque quelconque (ex : Qt) ou implémentation personnalisée "par toi meme" dans le pire des cas. Le principe de base étant d'essayer de travailler le plus souvent possible avec des unique_ptr et de n'utiliser des shared_ptr que lorsqu'il n'y a pas d'autre choix et que la décision de libérer la mémoire d'un pointeur doit réellement être prise de manière collégiale et partagée par différents éléments.

    Il y aurait encore beaucoup de choses à dire, mais bon, je crois que j'ai déjà écrit "mon quota" pour cette intervention. N'hésite pas à demander d'avantage de renseignements sur une notion abordée ici

Discussions similaires

  1. liens dans une liste: comportement etrange
    Par lapin_hobbit dans le forum Balisage (X)HTML et validation W3C
    Réponses: 3
    Dernier message: 08/06/2007, 14h14
  2. [LG]suppression dans une liste chainée
    Par mister_dsg dans le forum Langage
    Réponses: 9
    Dernier message: 16/12/2003, 22h20
  3. [langage] Comment rajouter des champs dans une liste
    Par toto_titi dans le forum Langage
    Réponses: 4
    Dernier message: 28/08/2003, 15h09
  4. Réponses: 2
    Dernier message: 17/08/2003, 21h07
  5. Réponses: 4
    Dernier message: 24/04/2003, 23h28

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