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

Langage C++ Discussion :

Problème sur des itérateurs


Sujet :

Langage C++

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut Problème sur des itérateurs
    Bonjour à tous,

    Je ne suis pas spécialement entraîné en C++ et je galère sur les itérateurs. Ca fait un petit moment que j'ai localisé une erreur que je ne comprends pas. Si vous pouviez m'aider à la résoudre...

    Il s'agit d'un bout de programme qui tente de lire deux listes imbriquées. Je m'explique :
    Dans la classe keyframespace il y a une liste statique de keyframespace. Chaque keyframespace a une map associant des String à des Quaternion.

    Je souhaite accéder aux quaternions de manière efficace, cad parcourir le moins de fois possible la liste.

    Du coup, j'esssaie de parcourir la liste de keyframespace, en effectuant un calcul sur chaque Quaternion de la map du-dit Keyframespace.

    Ce qui donne un truc comme ça :

    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<Keyframespace>::const_iterator iter  = (Keyframespace::getKeyFrameSpace()).begin();
            printf("Boucle principale entrée %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
     
        while (iter != Keyframespace::getKeyFrameSpace().end())
        {
        printf("Boucle principale entrée %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
     
        for( Keyframedesign::Keyframedesign_::const_iterator iterDesign = (*iter).getK()->Keyframe_.begin() ; iterDesign !=iter->getK()->Keyframe_.end();) { 
            printf("Ici AVANT : %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
     
        printf(iterDesign->first) ;
           /* Calculs n'affectant pas la boucle */
     
            ++iterDesign ;
     
            }
     
        printf("Ici APRES: %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
     
        ++iter ;
     
        printf("Sortie de boucle interne\n") ;
     
        }
     printf("Sortie de boucle principale\n");

    J'ai le résulat suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000 
    Boucle principale entrée 0.000000, 1.000000, 0.000000, 0.000000 
    Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000 
    BD
    Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000 
    BG
    Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000 
    JD
    Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000 
    JG
    Ici APRES: 0.000000, 1.000000, 0.000000, 0.000000 
    Sortie de boucle interne
    Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000 
    Erreur de segmentation
    En particulier
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000 
    Boucle principale entrée 0.000000, 1.000000, 0.000000, 0.000000
    Que je ne comprends pas.

    Merci pour votre aide.

  2. #2
    Invité
    Invité(e)
    Par défaut
    En reprenant ton code et nommant les différents printf :
    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<Keyframespace>::const_iterator iter  = (Keyframespace::getKeyFrameSpace()).begin();
            printf("Boucle principale entrée %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;   // (1)
     
        while (iter != Keyframespace::getKeyFrameSpace().end())
        {
        printf("Boucle principale entrée %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;  // (2)
     
        for( Keyframedesign::Keyframedesign_::const_iterator iterDesign = (*iter).getK()->Keyframe_.begin() ; iterDesign !=iter->getK()->Keyframe_.end();) { 
            printf("Ici AVANT : %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(),  iter->getDx(), iter->getDy()) ; // (3)
     
        printf(iterDesign->first) ;  // (4)
           /* Calculs n'affectant pas la boucle */
     
            ++iterDesign ;
     
            }
     
        printf("Ici APRES: %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ; // (5)
     
        ++iter ;
     
        printf("Sortie de boucle interne\n") ;  // (6)
     
        }
     printf("Sortie de boucle principale\n"); // (7)
    et qui correspond effectivement à ta sortie :
    (1) Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000
    (2) Boucle principale entrée 0.000000, 1.000000, 0.000000, 0.000000
    (3) Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000
    (4) BD
    (3) Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000
    (4) BG
    (3) Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000
    (4) JD
    (3) Ici AVANT : 0.000000, 1.000000, 0.000000, 0.000000
    (4) JG
    (5) Ici APRES: 0.000000, 1.000000, 0.000000, 0.000000
    (6) Sortie de boucle interne
    (2) Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000
    Donc ton erreur de segmentation se situe entre (2) (non compris) et (3) (compris) ce qui réduit le champs de recherche :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
     for( Keyframedesign::Keyframedesign_::const_iterator iterDesign = (*iter).getK()->Keyframe_.begin() ; iterDesign !=iter->getK()->Keyframe_.end();) { 
            printf("Ici AVANT : %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(),  iter->getDx(), iter->getDy()) ; // (3)
    Vu qu'une erreur de segmentation va de paire avec pointeur (ou référence), il faut en chercher un... Et vu que tes itérateurs me paraissent valides, j'aurais tendance à incriminer le pointeur retourné par iter->getK()

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut
    Oui c'est sans doute ce getK() qui pose problème. Cela dit, mon problème là c'est que la valeur du printf(1) et celle affichée par printf(2) sont différentes :/

    D'autre part, si j'écris
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
        printf("Avant incrementation : %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
        ++iter ;
        printf("Après incrémentation : %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
    A la place de seulement

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
        printf("Ici APRES: %f, %f, %f, %f \n", iter->getThetaX(), iter->getThetaY(), iter->getDx(), iter->getDy()) ;
        ++iter ;
    J'obtiens :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Avant incrémentation: 0.000000, 1.000000, 0.000000, 0.000000 
    Après incrémentation: 0.000000, 0.000000, 1.000000, 0.000000 
    Sortie de boucle interne
    Boucle principale entrée 0.000000, 0.000000, 0.000000, 0.000000
    Comment les valeurs pourraient-elles être différentes entre la fin de boucle et le début? Sans modification entre temps? =/ (i.e (4) et (2) devraient avoir mêmes valeurs)

  4. #4
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Citation Envoyé par Lyth_o Voir le message
    Comment les valeurs pourraient-elles être différentes entre la fin de boucle et le début?
    A vu de nez sans avoir regardé de trop près ton code, je dirais que vu le nombre d'indirections que tu as (liées à tous ces accesseurs), tu as une copie cachée quelque part qui fait que tu ne manipules pas toujours le même objet.
    En résumé : un peu de respect pour cette brave Déméter

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut
    Mmh, d'accord. Peut être bien. Je vois pas vraiment d'autre explication qu'un phénomène étrange pour le coup...

    Est-ce qu'il suffirait de faire des variables intermédiaires pour stocker les accès intermédiaires? Ou carrément restructurer le code =( ?

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Lyth_o Voir le message
    Ou carrément restructurer le code =( ?
    Ca clarifiera certainement ton design.

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut
    Pour être plus précis. J'ai trouvé la source exacte de l'erreur :

    Si je fais


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    list<Keyframespace>::iterator iter  = (Keyframespace::getKeyFrameSpace()).begin();
    iter++ ;
    printf("%p", iter->getK()) ;
    J'ai bien une valeur.

    Si je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    list<Keyframespace>::iterator iter  = (Keyframespace::getKeyFrameSpace()).begin();
    list<Keyframespace>::iterator iterFin  = (Keyframespace::getKeyFrameSpace()).end() ;
    iter++ ;
    printf("%p", iter->getK()) ;
    Je reçois nil.

    Il semblerait que ce soit l'accès à la méthode statique qui ne lui plaît pas. Peut être est-ce déconseillé davoir dans une classe une liste statique comportant des éléments de la même classe?

    Dans tous les cas je vais changer cette classe..; La découper en deux classes. Voir si ça améliore mon cas.

  8. #8
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Ca a peu probablement à voir avec static mais plus surement à la façon dont tu fais les retours ou à ce qui est fait à la liste dans les différentes fonctions. Si Keyframespace::getKeyFrameSpace a un retour par valeur, cela pourrait expliquer bien des choses car alors tu aurais bien une copie ... détruite juste après et donc avec un itérateur invalide :

    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
    #include <list>
     
     
    struct exemple
    {
     
        static std::list<int> error_prone_get_list()
        {
     
            return instance().ma_list;
        }
        static std::list<int> const & correct_get_list()
        {
            return instance().ma_list;
        }
     
    private:
        exemple()
        {
            ma_list.push_back(0);
            ma_list.push_back(1);
            ma_list.push_back(2);
            ma_list.push_back(3);
        }
        ~exemple()
        {}
     
        static exemple const& instance()
        {
            return mon_instance;
        }
     
        static exemple mon_instance;
        std::list<int> ma_list;
     
    };
    exemple exemple::mon_instance;
     
     
    #include <algorithm>
    #include <iterator>
    #include <iostream>
    int main()
    {
        // plantage assurée
        std::copy(
                // la liste est renvoyé par copie (error_prone_get_list), 
                // on récupère l'itérateur
                // puis on détruit la liste
                // => l'itérateur devient invalide
            exemple::error_prone_get_list().begin(), 
            exemple::error_prone_get_list().end()
            ,std::ostream_iterator<int>(std::cout,"\n")
        );
     
        // avec l'interface dangereuse :
        std::list<int> the_list = exemple::error_prone_get_list(); // on fait une copie de la liste
     
        std::fill(
            // on prend les itérateurs de la copie de la liste
            the_list.begin(),
            the_list.end(),
            42
        );
        std::copy(
            the_list.begin(),
            the_list.end()
            ,std::ostream_iterator<int>(std::cout,"\n")
        );
        // ici, la liste copié (the_list) est encore valide
        // mais la liste dans mon_instance est inchangée
     
     
        std::cout<<"\n\n";
        std::copy(
            exemple::correct_get_list().begin(),
            exemple::correct_get_list().end()
            ,std::ostream_iterator<int>(std::cout,"\n")
        );
     
        return 0;
    }

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut
    C'est exactement ça ^^
    En fait j'airéussi à l'instant à contourner le problème en renvoyant un itérateur directement. En suivant la loi de Démeter dont tu m'as parlé.

    Cependant, je vais essayer ta méthode qui me semble plus esthétique. Je dois avouer que je ne connais pas grand chose en c++ (pas fait de tutorial ni rien, je procède par analogie avec C et Java...). Et j'ai effectivement pas fait attention au retour de la fonction...

    Merci beaucoup en tout cas. Je devrais m'en sortir maintenant.

    Edit : Ta méthode marche à merveille =) Je viens de lvl up en c++ lol :p

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,

    L'exemple en code était là pour illustrer le problème. Changer le getter pour qu'il retourne une référence corrige ponctuellement un problème de code qui ne faisait que traduire un design probablement chancelant.

    Tu plonges dans l'eau glacée : ok t'as plus de fièvre mais tu as probablement encore la grippe

    La solution passe certainement par un redesign de tes classes.

    Et accessoirement, pour Demeter, ce n'est pas tant un objectif de style qu'un bon indicateur que tu as un problème de design (interfaces trop pauvres, mauvaises abstractions, trop fort couplage, etc...)

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    17
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 17
    Par défaut
    Quand tu dis interface, tu parles de l'utilisation de namespace ?
    J'ai juste une classe imbriquée dans une autre.. Et je me sers des deux dans un namespace.

    Keyframespace utilise Keyframedesign (en attribut).
    Keyframedesign n'utilise rien de spécial.

    Je veux bien changer l'architecture de ces classes... Mais vue qu'elles ne font qu'une dizaine de lignes chacune, je vois pas trop comment...

    Quant au couplage... C'est vrai que j'ai du mal à comprendre la notion. Je vois à quoi ça fait référence mais je n'ai pas d'exemple de chose mauvaise, à ne pas faire, en tête. Du coup mon code ne me semble pas trop couplé...

  12. #12
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Citation Envoyé par Lyth_o Voir le message
    Quand tu dis interface, tu parles de l'utilisation de namespace ?
    J'emploie probablement le mauvais vocabulaire. Je pense plutôt que contrat ou type abstrait de données seraient plus proches. Disons que c'est ce à quoi s'engage ta classe. Les classes que tu présentes ont l'air d'être un amoncellement de fonctions, sans que leur responsabilité (ce qu'elles sont chargées de faire en tant que classe) soit bien définie ni comment cette responsabilité est mise en œuvre.

    Citation Envoyé par Lyth_o Voir le message
    Je veux bien changer l'architecture de ces classes... Mais vue qu'elles ne font qu'une dizaine de lignes chacune, je vois pas trop comment...
    Prend une feuille et raisonne avec des 'concepts'. Regarde comment ils doivent s'articuler entre eux. Cela devrait t'aider à identifier ton design. N'hésites pas à mettre ton design en revue.

    Citation Envoyé par Lyth_o Voir le message
    Quant au couplage... C'est vrai que j'ai du mal à comprendre la notion. Je vois à quoi ça fait référence mais je n'ai pas d'exemple de chose mauvaise, à ne pas faire, en tête. Du coup mon code ne me semble pas trop couplé...
    Si je prends une classe au hasard, combien dois-je en prendre d'autres pour réussir à la faire compiler ? Exécuter ? Est-ce normal d'avoir à les tirer ? Quelles dépendances sont introduites par l'en-tête ? Par l'implémentation ?

    Certains couplages forts sont normaux. Ils représentent un service cohérent et constituent alors une 'bibliothèque' (même si l'interface externe est moins riche et couplée que l'implémentation interne).
    Quand tu te rends compte que le couplage n'a pas lieu d'être, il faut alors travailler sur les bonnes abstractions et/ou concepts => héritage + générique

Discussions similaires

  1. Problème sur des chaines de caractères
    Par soso78 dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 16/10/2007, 13h11
  2. Réponses: 1
    Dernier message: 02/07/2007, 15h57
  3. PHP et IIS Problème sur des repertoires virtuels
    Par remi_neo dans le forum IIS
    Réponses: 1
    Dernier message: 30/05/2007, 17h17
  4. [MySQL] Problème sur des comptes (login/mdp)
    Par vincedjs dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 13/03/2006, 15h41
  5. Problème sur des chaînes de caractères
    Par Anonymous dans le forum Access
    Réponses: 9
    Dernier message: 16/09/2005, 08h21

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