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

SL & STL C++ Discussion :

[STL] Probleme STL : List : Iterator


Sujet :

SL & STL C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    129
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 129
    Points : 68
    Points
    68
    Par défaut [STL] Probleme STL : List : Iterator
    Bonsoir,
    Suite a differrente remarque je me suis mis a la STL et je trouve ca pas mal du tout
    J'ai donc voulu convertir mon code afin de prendre possesion des avantages de la STL.
    Malheureusement... je me vois dans l'incapacitee de debugueer le probleme ici present. L'erreur est un classic "Segmentation fault" et voici une partie de la trace effectuee avec gdb :

    fillBin (tabBin=0x80c381c, tabSeg=0x80bbe30, tabVertices=0x80bc0c0, nbSeg=162) at visual12.cpp:1393
    1393 if(nbDelList<2) // if(delList is not Full)
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1395 cout<<(*iter)<<"** added to delList["<<nbDelList<<"]."<<endl<<endl;
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    0x80bf910** added to delList[0].

    1396 delList[nbDelList]=(*iter);
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1397 if((*iter)->getActivity()==true)
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1399 (*iter)->setActivity(false);
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1400 workingSegments.erase(iter);
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1401 numWorkingSegments--;
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1403 nbDelList++;
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1388 for(iter=workingSegments.begin(); iter!= workingSegments.end(); ++iter)
    1: *iter = (Line *&) @0x80bb740: 0x80bf910
    (gdb) next
    1390 cout<<"Vertices : "<<(*iter)->getPtIni()<<" and "<<(*iter)->getPtFin()<<" belong to WorkingSegment : "<<*iter<<endl;
    1: *iter = Disabling display 1 to avoid infinite recursion.
    (Line *&) @0x8: Cannot access memory at address 0x8

    Voici le code en question :

    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
     
    if(iVertices>0)
    {	
    cout<<"Current Vertices : "<<vCurrent<<"and alpha = "<<vCurrent->getAngle()<<endl;
     for(iter=workingSegments.begin(); iter!= workingSegments.end(); ++iter)
    {
              cout<<"Vertices : "<<(*iter)->getPtIni()<<" and "<<(*iter)->getPtFin()<<" belong to WorkingSegment : "<<*iter<<endl;
    	  if(((*iter)->getPtIni()==vCurrent) || ((*iter)->getPtFin()==vCurrent))
    	 {
    		if(nbDelList<2) // if(delList is not Full)
    		{	
    			cout<<(*iter)<<"** added to delList["<<nbDelList<<"]."<<endl<<endl;
    			delList[nbDelList]=(*iter);
    		         if((*iter)->getActivity()==true)
    			{
    				(*iter)->setActivity(false);
    				workingSegments.erase(iter);
    				numWorkingSegments--;
    			}
    			nbDelList++;
    		}
    	}
    }
    Pourquoi donc il n'arrive pas a acceder a la memoire ??? Je suppose que cela vient de l'iterator.. mais ?

    Merci encore !

  2. #2
    Membre expérimenté
    Avatar de coyotte507
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    1 327
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 327
    Points : 1 452
    Points
    1 452
    Par défaut
    tu fais mal ton erase (voir FAQ).

    Ouh là là l'erreur était bien cachée

    selon ce que j'en ai compris, il faut récupérer l'itérateur retourné par la fonction erase() au lieu d'incrémenter l'ancien itérateur. Je sais pas pk.

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    129
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Merci.... j'ai continue la FAQ et finalement trouve !
    Parfait

    Contenu de la FAQ qui se trouve ici :
    #include <vector>

    std::set<int> s;
    for (std::vector<int>::iterator it = s.begin(); it != s.end(); )
    {
    if (*it == 5)
    it = s.erase(it);
    else
    ++it;
    }

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

    Informations professionnelles :
    Activité : aucun

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

    Il y a plusieurs particularités à prendre en compte:

    Principalement, il faut savoir que la fonction erase() des conteneurs rend l'itérateur invalide
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    for(std::list<int>::iterator it=malist.begin();it!=malist.end();it++)
    {
        malist.erase(it);/*SEGVAULT: it devient invalide lors de l'efacement*/
    }
    Et c'est normal: un itérateur n'est souvent qu'un pointeur sur l'élément du conteneur en cours de traitement... Si tu efface l'élément, comment veux tu arriver à récupérer l'élément qui se trouve avant ou apres quelque chose qui n'existe plus

    Ton code *pourrait* donc éventuellement fonctionner 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
     
    /* dans la boucle */
        if((*iter)->getActivity()==true)
            {
                (*iter)->setActivity(false);
                if(iter!=workingSegments.begin())
                {
                    std::list<iterator>::tempiter=iter--;
                    workingSegments.erase(iter);
                    iter=tempiter;
                }
                else
                {
                    workingSegments.erase(iter);
                    iter=workingSegments.begin();        
                }
                numWorkingSegments--;
            }
    dont le test indiqué a pour but d'éviter les problèmes au cas où le premier élément de la liste venait à etre supprimé...

    Tu peux peut etre envisager d'avoir recours à un remove_if() qui pourrait faciliter les choses (plusieurs sujets en ont traité dernièrement )

    Ensuite, il est intéressant de savoir comment est déclarée ta liste workingSegments...

    Si elle est déclarée comme contenant simplement ta classe, c'est à dire sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::list<taclasse> workingSegments;
    tu ne dois pas faire un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     cout<<"Vertices : "<<(*iter)->getPtIni()<<" and "<<(*iter)->getPtFin() /* cut */
    mais un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     cout<<"Vertices : "<<(*iter).getPtIni()<<" and "<<(*iter).getPtFin()/*cut*/
    Si, par contre, elle est déclarée sous forme d'une liste de pointeur sur le type de ta classe, c'est à dire sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::list<taclass*> workingSegments;
    il faut savoir que tu t'expose à des fuites mémoires lors de l'effacement des éléments...

    En effet, le code d'affichage est alors correct, mais, d'un autre coté, on s'attend à ce que chaque élément de la liste ai été créé dynamiquement (avec new), et donc, il faut libérer dynamiquement la mémoire qui lui a été allouée, avant de perdre l'adresse à laquelle il se trouve, si l'élément n'est pas géré sous forme de shared_ptr...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Ceci dit, je sais qu'on peut tres bien se passer de n'importe quel argument dans une boucle pour et qu'on a donc des codes tout à fait valides sous la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for( ; ; )
    /* ou */
    for(it=begin; ; )
    /* ou */
    for(it=begin; it!=end; )
    (enfin, pour autant que it, begin et end correspondent à quelque chose de valide), mais, à titre purement personnel, j'aurais tendance à les remplacer par des boucles while tout ce qu'il y a de plus normal...

    Surtout dans le cadre du code fournis à l'origine...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(iter=workingSegments.begin(); iter!= workingSegments.end(); ++iter)
    tel qu'il était représenté à l'origine... et qui sous entend qu'il y a, avant la boucle, une déclaration de iter comme étant un itérateur sur la liste... Une boucle tant ment beaucoup moins sur ce qu'elle fait qu'une boucle itérative à mon gout

    On pourra m'objecter que tout l'intéret du code
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    for (std::vector<int>::iterator it = s.begin(); it != s.end(); )
    {
        if (*it == 5)
            it = s.erase(it);
        else
            ++it;
    }
    réside dans le fait que it est une variable "super locale", qui est détruite une fois que la boucle est quittée, mais cet intéret est absent dans le dans le cas du code d'origine

  6. #6
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par koala01
    par contre, elle est déclarée sous forme d'une liste de pointeur sur le type de ta classe, c'est à dire sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::list<taclass*> workingSegments;
    il faut savoir que tu t'expose à des fuites mémoires lors de l'effacement des éléments...
    Dans ce cas, il y a boost:ptr_list (conteneur intelligent)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    boost::ptr_list<taclasse> workingSegments;

  7. #7
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    129
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Je ne m'attendais pas a autant de reponse ! Merci beaucoup !
    Alors pour les shared pointer de chez boost je crois, j'avais vu que ca me simplifirais la vie, mais je voulais d'abord bien comprendre le principe des list de la STL. Il me semble que le prinicpe d'iterateur est maintenant clair. Simplement je pensais que la STL avait ete faite pour simplifier la vie et donc si je dois a nouveau sauvegarder l'iterateur puis supprimer le bon et repartir avec mon iterateur... je vois pas trop en quoi ca simplifie
    Pour le boost:ptr_list (conteneur intelligent) je vais voir ca aussi !
    Merci dans tous les cas !

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Il ne faut pas confondre "faciliter la vie de l'utilisateur" et "faire du grand n'importe quoi"...

    Un itérateur n'est qu'une sorte de curseur qui indique l'élément du conteneur sur lequel nous allons travailler...
    • On peut accéder à l'élément qui le précede ou à celui qui le suit (dans les limites de la validité, évidemment)
    • On peut accéder à la valeur qu'il représente
    • On peut décider de rajouter un élément avant ou de supprimer l'élément


    Avouve que ce n'est déjà pas si mal

    Le conteneur, pour sa part, s'assure de l'ensemble de la gestion de la mémoire réservée aux différents éléments, et c'est en définitive ce qu'on lui demande

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Juillet 2007
    Messages
    14
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2007
    Messages : 14
    Points : 8
    Points
    8
    Par défaut suppression d'un objet dans un vector
    Bonjour à tous,
    en faite, j'ai un problème concernant les vecteurs de pointeurs,
    Dans une méthode "Get_Objects_Coverd_P"
    Je fais un parcours sur un vecteur de pointeurs "table" qui sont des objets possedant un nom ,un min et un max. Parmi les objets stockés, je voulais récupérer les objets qui sont inclus dans un objet P bien défini (c'est à dire ,la borne inf d'un objet est >= à lla borne inf de P et la borne sup d'un objet est <= par rapport à P)
    les objets retenus sont stockés dans un nouveau vecteur de pointeurs qui s'appelle "Template_Object_Covered_P". et doivent être suuprimés du vecteur "table".
    j'ai utilisé erase pour les effacer mais ça fonctionne pas.les objets ne s'effacent pas.
    par contre quand j'applique ça dans main sans passer par une méthode ça marche.
    A votre avis ,est ce que c'est à cause que je travaille sur des pointeurs???
    Aidez moi
    ci dessous le code :







    /*************************************Objets Couverts par P**************************************************************/
    vector<Object*> Get_Objects_Coverd_P(vector<Object*>table){
    vector<Object*>Template_Object_Covered_P;
    Object* OD;
    Object* P;
    int ind_p;

    /***********************************Recherche de l'objet dominant*********************************************************/
    OD = table.front();
    cout <<"L'objet dominant est : "<<OD ->Get_Name()<<endl;

    /***************************************Recherche d'un objet en intersection partielle avec l'objet dominant**************/
    P = Get_P(table); // P est déjà calculé

    /*************************Recherche des objets couverts par l'objet P ****************************************************/
    if(P!=NULL){
    /**************************On cherche dans la liste initiale**************************************************************/
    Template_Object_Covered_P.clear();
    for(ind_p=1;ind_p<table.size();ind_p++){
    if((table[ind_p]->Get_Min()>=P->Get_Min())&&(table[ind_p]->Get_Max()<=P->Get_Max())){
    Template_Object_Covered_P.push_back(table[ind_p]);
    table.erase(table.begin()+ind_p); // Le problème est ici
    ind_p--;
    }
    }
    return Template_Object_Covered_P;
    }
    }




    /******************************************************MAIN********************************************************/
    int main()
    {
    char fileName [LGMAX_FILE_NAME + 1] ;
    string name;
    int min, max;
    bool istemplate;
    int nb_objects=0;
    int i;
    string Z_String ;
    vector<Object*> table_objects;
    vector<Object*> objects_covered_P;


    /**************Lecture des informations dans le fichier qui contient les noms des objets leurs Xmin et leurs Xmax************/
    cout << "name of the file : " ;
    cin >> setw (LGMAX_FILE_NAME) >> fileName ;
    ifstream entree (fileName, ios::in|ios::binary) ; // ou ios::in
    if (!entree) { cout << "Error: can not open the file " << fileName <<endl ;
    exit (-1) ;
    }

    while(!entree.eof())
    {
    entree >> name;
    entree >> min;
    entree >> max;
    if(name == "*") break;
    else
    cout << "name: " << name << " min: " << min << " max: " << max << endl ;
    table_objects.push_back(new Object(name,min,max,false));
    nb_objects++;
    }

    entree.close () ;
    cout << "**************************************************************\n";
    cout << " Voici les noms, les min, les max des objets de votre image \n";
    cout << "**************************************************************\n";
    cout << "Nb objects: " << nb_objects << endl;


    for(i= 0; i< nb_objects;i++){
    cout<<table_objects[i]->Get_Name()<<"\t"<<table_objects[i]->Get_Min()<<"\t"<<table_objects[i]->Get_Max()<<"\n";
    }
    cout << "Taille du vecteur d'objets: " << table_objects.size()<<"\n";

    objects_covered_P = Get_Objects_Coverd_P(table_objects);
    cout<<"les objets couverts par P sont :"<<endl;
    for(int y=0;y<objects_covered_P.size();y++)
    cout<<objects_covered_P[y]->Get_Name()<<"\t";
    cout<<endl;


    /*for(int z=0;z<table_objects.size();z++){
    table_objects.erase(table_objects.begin()+z);
    z--;
    }
    cout<<endl;*/

    cout<<"Table Objects contient :"<<endl;
    for(int k=0;k<table_objects.size();k++)
    cout<<table_objects[k]->Get_Name()<<"\t";
    cout<<endl;
    }

  10. #10
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    129
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Citation Envoyé par koala01
    Il ne faut pas confondre "faciliter la vie de l'utilisateur" et "faire du grand n'importe quoi"...

    Un itérateur n'est qu'une sorte de curseur qui indique l'élément du conteneur sur lequel nous allons travailler...
    • On peut accéder à l'élément qui le précede ou à celui qui le suit (dans les limites de la validité, évidemment)
    • On peut accéder à la valeur qu'il représente
    • On peut décider de rajouter un élément avant ou de supprimer l'élément


    Avouve que ce n'est déjà pas si mal

    Le conteneur, pour sa part, s'assure de l'ensemble de la gestion de la mémoire réservée aux différents éléments, et c'est en définitive ce qu'on lui demande
    Oui en effet, mais n'aurait-il pas ete plus logique de ne pas rendre l'iterateur invalide ? C'est juste que je trouve bizare de ne pas gerer cela. Mais dans son ensemble je suis assez satisfait

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    le probleme réside dans "comment ne pas rendre l'itérateur invalide"

    En renvoyant l'élément précédent oui, mais, et si c'est le premier du conteneur

    En renoyant l'élément suivant et si c'est le dernier
    Et, quoi qu'il en soit, tu trouvera toujours quelqu'un qui aurait préféré que ce soit l'autre optique qui aie été choisie

    En plus, comme je l'ai indiqué, un itérateur n'est jamais qu'un "curseur" qui indique quel est l'élément en cours d'utilisation... Si tu supprime l'élément indiqué, le "curseur" indique quelque chose d'invalide

  12. #12
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    129
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2004
    Messages : 129
    Points : 68
    Points
    68
    Par défaut
    Citation Envoyé par koala01
    le probleme réside dans "comment ne pas rendre l'itérateur invalide"

    En renvoyant l'élément précédent oui, mais, et si c'est le premier du conteneur

    En renoyant l'élément suivant et si c'est le dernier
    Et, quoi qu'il en soit, tu trouvera toujours quelqu'un qui aurait préféré que ce soit l'autre optique qui aie été choisie

    En plus, comme je l'ai indiqué, un itérateur n'est jamais qu'un "curseur" qui indique quel est l'élément en cours d'utilisation... Si tu supprime l'élément indiqué, le "curseur" indique quelque chose d'invalide
    Je ne peux être que d'accord , si tu peux jeter un oeil à mon nouveau problème

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. probleme conteneur <list> de la bibliotheque STL
    Par khaledmoez dans le forum C++
    Réponses: 2
    Dernier message: 06/12/2009, 18h48
  2. STL : retirer une liste d'une liste
    Par DEVfan dans le forum SL & STL
    Réponses: 13
    Dernier message: 05/01/2007, 20h49
  3. [STL]Afficher une liste de listes avec copy
    Par boromir73 dans le forum SL & STL
    Réponses: 3
    Dernier message: 27/10/2006, 15h23
  4. Probleme de liste STL
    Par flipper203 dans le forum SL & STL
    Réponses: 18
    Dernier message: 17/07/2006, 13h49
  5. Probleme de list STL et recherche
    Par flipper203 dans le forum SL & STL
    Réponses: 17
    Dernier message: 30/06/2006, 10h10

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