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 :

Itérateur n'arrivant pas à end()


Sujet :

C++

  1. #1
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    29
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2007
    Messages : 29
    Par défaut Itérateur n'arrivant pas à end()
    Bonjour à tous.

    J'utilise un itérateur pour parcourir une liste (de la bibliothèque standard), avec une boucle for, de ce type
    for(p1 = maListe.begin();p1 != maListe.end();p1++)
    L'éxecutable plante (segmentation fault) en arrivant à cette boucle.
    J'ai découvert en fait que p1 ne prenait jamais la valeur maListe.end(), et c'est donc l'action ++ qui fait planter en lui demandant de pointer vers quelque chose qui n'existe pas, car :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(p1 != maListe.end())
    {
    p1++;
    }
    plante également, tandis que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int i =0;
    std::list<Ma_Classe>::iterator p1;
    while(i<maListe.size())
    {
    i++;
    p1++;
    }
    Fonctionne.

    J'ai cherché sur Google, mais je n'ai pas trouvé de pages correspondant à mon problème.
    Si vous avez une piste, je suis preneur.
    Merci d'avance.

  2. #2
    Membre chevronné
    Inscrit en
    Novembre 2006
    Messages
    362
    Détails du profil
    Informations forums :
    Inscription : Novembre 2006
    Messages : 362
    Par défaut
    Salut,

    Poste ton code, on ne pourra pas t'aider sans cela.

    L'erreur est sans doute dans la partie de ton code que tu ne mentionne pas parce que tu penses que c'est évident.

    Bonne journée.

  3. #3
    Membre éclairé Avatar de ZaaN
    Inscrit en
    Novembre 2005
    Messages
    819
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 819
    Par défaut fonction qui marche


    Comme il y a trop peu d info pour trouver ton problème, je te propose un code pour faire une recherche dans une list de ton type. Ce code est tres facilement adaptable a tes besoins je suppose.

    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
    bool MaClasse::ChercheDansListe(PARAM _CriterDeRecherche,MonTypeDeList::iterator &_MonIterateur)
    {
    	if (!m_MaListe.empty())
    	{				
    		_MonIterateur=m_MaListe.begin();//parcours de la liste
    		for(_MonIterateur;_MonIterateur!=m_MaListe.end();_MonIterateur++)
    		{			
    			if ((*_MonIterateur)->VerficationDuCritereDeRecherche()==_CriterDeRecherche)
    			{																
    				return true;
    			}			
    		}		
    	}	
    	_MonIterateur=m_MaListe.end();
    	return false;
    }
    Si la fonction retourne vrai, tu utilises l iterateur pour acceder au premier objet qui remplissait les condition de recherche.

  4. #4
    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 : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Linschn n'a pas indiqué si c'était une recherche qu'il voulait faire. Enfin c'est une bonne piste, vu qu'habituellement ce sont les suppressions (mal faites) qui provoquent ce genre de comportement ; c'est d'ailleurs pour cela qu'on en parle dans la FAQ.

    Pour en revenir à la recherche, il y a std::find et std::find_if.

  5. #5
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    29
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2007
    Messages : 29
    Par défaut
    Merci de vos réponses,

    Tout d'abord, le code de la fonction telle qu'elle devrait être :
    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
     
    bool EK_Maillage::noeudsLies(class EK_Noeud noeud1,class EK_Noeud noeud2)
    {
       std::list<class EK_Noeud_M>::iterator p1;
       std::list<class EK_Noeud>::iterator p2;
       for(p1 = me.begin();p1 != me.end();p1++)
         {
           printf("DEBUG:A,%i\n",me.size());
           if((*p1).getCoord()== noeud1)
     	{
     	  for(p2 = (*p1).getVoisinage().begin();p2 != (*p1).getVoisinage().end();p2++)
     	    {
     	      if((*p2) == noeud2)
     		{
     		  return true;
     		}
     	    }
     	  return false;
     	}
         }
    }
    En clair, on trouve noeud1 dans me, une fois qu'on l'a trouvé, on regarde si noeud 2 est dans la liste de ses voisins, et on renvoie la réponse.
    Voilà le code source de la fonction à l'heure actuelle, suivi de la sortie standard.
    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
     
    bool EK_Maillage::noeudsLies(class EK_Noeud noeud1,class EK_Noeud noeud2)
    {
       std::list<class EK_Noeud_M>::iterator p1;
       std::list<class EK_Noeud>::iterator p2;
       for(p1 = me.begin();p1 != me.end();p1++)
         {
           printf("DEBUG:A,%i\n",me.size());
           if((*p1).getCoord()== noeud1)
     	{
    	  p2 = (*p1).getVoisinage().begin();
    	  int i;
    	  for(i = 0;i < (*p1).getVoisinage().size();i++)
    	    {
    	      printf("DEBUG:A1\n");
    	      p2++;
    	    }
    	  p2 = (*p1).getVoisinage().begin();
    	  while(p2 != (*p1).getVoisinage().end())
    	    {
    	      printf("DEBUG:A2\n");
    	      p2++;
    	    }
     	  printf("DEBUG:B%i\n",(*p1).getVoisinage().size());
     	  for(p2 = (*p1).getVoisinage().begin();p2 != (*p1).getVoisinage().end();p2++)
     	    {
     	      printf("DEBUG:C");
    // 	      if((*p2) == noeud2)
    // 		{
    // 		  return true;
    // 		}
     	    }
     	  return false;
     	}
         }
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    DEBUG:A,4
    DEBUG:A,4
    DEBUG:A1
    DEBUG:A2
    DEBUG:A2
    Erreur de segmentation (core dumped)
    Une seule occurence de DEBUG:A1 est normale, ma liste ne contient qu'un seul élément au début de l'algorithme.

  6. #6
    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 : 41
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Par défaut
    Ca sent le retour par valeur pour getVoisinage().

  7. #7
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Citation Envoyé par Laurent Gomila
    Ca sent le retour par valeur pour getVoisinage().
    Définitivement. Vu les drôles de copies dans le reste du code, et le syndrôme de chaînage de fonctions, cela me parait la meilleure hyppothèse.

    Ca ou une race condition, mais tu ne pourrais pas la reproduire aussi facilement que ça.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  8. #8
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    29
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2007
    Messages : 29
    Par défaut
    Bonjour !

    Je ne voyais pas ce qu'était le retour par valeur, mais j'ai lu mon bouquin, j'en conclus que je dois faire un passage de valeur par référence.

    Deux questions cependant : en quoi le passage par valeur (outre l'occupation mémoire inutile) est-il un problème ?
    Cette question vient du fait que nulle part je n'ia fait de passage par référence, et que le problème va donc se reproduire...

    Qu'est-ce qu'une race condition ?

    Et les questions bonus :
    Qu'entends-tu par droles de copies ? Comment éviter les enchainements de fonctions ?
    soit, en plus simple : Je débute comme vous devez maintenant vous en douter, quelles sont les bonnes habitudes à prendre pour éviter ça ?

    Je vous remercie de vos réponses, je modiefierai le code dans le Week end, et posterai $(si cela fonctionne).

  9. #9
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Citation Envoyé par Linschn
    a- Je ne voyais pas ce qu'était le retour par valeur, mais j'ai lu mon bouquin, j'en conclus que je dois faire un passage de valeur par référence.

    b- Deux questions cependant : en quoi le passage par valeur (outre l'occupation mémoire inutile) est-il un problème ?
    Cette question vient du fait que nulle part je n'ia fait de passage par référence, et que le problème va donc se reproduire...

    c- Qu'est-ce qu'une race condition ?

    d-Et les questions bonus :
    Qu'entends-tu par droles de copies ? Comment éviter les enchainements de fonctions ?
    soit, en plus simple : Je débute comme vous devez maintenant vous en douter, quelles sont les bonnes habitudes à prendre pour éviter ça ?
    a-
    "Passage" est généralement utilisé dans le contexte de "passage d'argument".
    Pour les retours de fonctions, on parle de "retour" -- la source de ton bug est un mélange construit autour d'un retour par valeur.

    Dans la terminologie que j'utilise, en gros: les deux peuvent être par valeur ou par référence. Les par valeur implique que ce sont des valeurs qui circulent en étant copiées -- je préfère parfois parler de passage par copie. Le par-référence (aka par-adresse) impliquement que ce sont des pointeurs ou références qui circulent (i.e. ce sont les adresses qui sont copiées dans la pile, et non les objets).

    b- Les problèmes des par-valeurs sont:
    - coute cher sur les gros objets (en gros, plus gros qu'un à deux int)
    - nécessite que la donnée soit copiable (attention aux sémantiques entité/valeur, et aux ressources possédées)

    par-adresse:
    - indirection
    - coute plus cher sur les petits objets

    Les problèmes de retours par adresse:
    - il faut que l'adresse (/référence) de l'entité retournée soit toujours valide à la fin de l'exécution de la fonction
    - Donne accès à une entité, et pas seulement sa valeur à un instant donné.

    Dans ton cas très particulier, tu enchaines les begin() et end() sur une donnée dont tu retournes une copie. Résultat, à chaque fois que tu fais ton get(), c'est une nouvelle entité itérable que tu retournes. Tu te retrouves avec un begin() et un end() qui pointent vers deux entités différentes. Pire, après tes appels à begin/end, aucune de ces deux entités n'existe plus dans ton code.

    Deux solutions:
    - soit le voisinage que tu retournes continue d'exister après le get() (typiquement, tu retournes une donnée membre), alors retournes une référence constante sur ta donnée membre, et tu pourras utiliser tes chainages.
    - soit le voisinage est construit à la volée à partir d'autres infos de ton objet, alors tu es obligé de procéder à un retour par copie, et tu ne pourras pas chainer immédiatement en appellant begin/end. A la place, stockes ce qui est retourné dans une variable temporaire nommée.

    Il y a aussi une tierce solution qui réduit le couplage aux sous-objets.
    Expose dans ton objet une fonction qui va réaliser la recherche qui t'intéresse. Avec ça, aucun chainage, et une bien meilleure encapsulation.
    Dit autrement : rajoutes une fonction aPourVoisin(Noeud const&) dans ta classe Noeud.

    c- C'est quand deux threads manipulent une même donnée et qu'un des deux threads altère significativement la donnée tandis que l'autre est en train d'y accèder. Celui en cours d'accès a alors une vision incohérente de la donnée et tout peut arriver, généralement rien de bon.

    d- On ne met pas "class" dans les signatures des fonctions.

    Bonnes habitudes => raffinages, rôles simples et bien déterminés (ou encore "non à la tyrannie des accesseurs"), encapsulation, ... Il y a tellement de choses.



    NB: tout ce que j'ai dit est pinaillable.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  10. #10
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    29
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2007
    Messages : 29
    Par défaut
    Après rajout du retour par référence (c'est bien une donnée membre), tout fonctionne !
    Je vais néanmoins écrire une fonction aPourVoisin(int) et aPourVoisin(Noeud), qui serviront respectivement au parcours dans une boucle for et à la recherche d'un noeud précis.

    Merci beaucoup de votre aide précise et rapide.


    Si je mets class tout le temps c'est pour indiquer à emacs que je veux que EK_Noeud soit écrit en violet, pas en vert. Il faut que je trouve une autre solution.

    Je n'ai plus qu'à nettoyer mon code : mettre des retours et des passages par référence à peu près partout, enlever les class dans les signatures également.

  11. #11
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Citation Envoyé par Linschn
    mettre des retours et des passages par référence à peu près partout
    Constante la référence. Constante!
    Définir un accesseur qui donne une contrôle total à la donnée encapsulée .. autant ne pas la mettre privée. Au moins on ne fait pas semblant d'encapsuler quoique ce soit.
    => FAQ.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

  12. #12
    Membre averti
    Inscrit en
    Janvier 2007
    Messages
    29
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Janvier 2007
    Messages : 29
    Par défaut
    Effectivement, je viens de comprendre cet aspect de la chose.
    Merci

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

Discussions similaires

  1. [Kylix 3] Je n'arrive pas à utiliser MySQL
    Par usebob dans le forum EDI
    Réponses: 4
    Dernier message: 15/04/2005, 10h18
  2. problème que je n'arrive pas à résoudre de façon récursive
    Par miam dans le forum Algorithmes et structures de données
    Réponses: 9
    Dernier message: 31/07/2004, 11h21
  3. [Function] N'arrive pas à sortir
    Par bouboussjunior dans le forum ASP
    Réponses: 3
    Dernier message: 14/06/2004, 16h36
  4. Je n'arrive pas à détruire une fenêtre
    Par CORREGE Frédéric dans le forum MFC
    Réponses: 6
    Dernier message: 22/02/2004, 20h28
  5. j'arrive pas a arreter mon thread d'arriere-plan
    Par ms91fr dans le forum Langage
    Réponses: 6
    Dernier message: 06/06/2003, 21h36

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