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 :

quelque chose que je n'ai pas compris (avec iterator)


Sujet :

C++

  1. #1
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Avril 2010
    Messages : 85
    Points : 61
    Points
    61
    Par défaut quelque chose que je n'ai pas compris (avec iterator)
    Bonjour,

    voilà je me remets au dev C++. Et boum erreur de segmentation !
    J'ai réduit... réduit le code que voici. J'explique.

    J'ai 2 vector de pointeurs : vector<Graphe*>vG et vector<Reference*>vG

    - une Reference contient un un Graphe*
    - un Graphe peut produire une nouvelle Reference*

    on peut donc ajouter au vector une nouvelle Reference* produite par un Graphe* lui meme dans une Reference (du vector). un peu.

    le probleme est que quand je fait cette operation a partir d'un iterator du vector<Reference*> Celui est modifié.
    Consequence Seg fault !

    le code (fichier unique main.cpp):
    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
     
    #include <cstdlib>
    #include <vector>
    #include <algorithm>
    #include <iostream>
     
    class Reference; //declaration
     
    /****************
    * les classes   *
    ****************/
    class Graphe {
        private:
            Graphe* parent;
            std::vector<int> feuilles;
     
        public:
            Graphe(Graphe* par) : parent(par){/***/};//constructeur
            ~Graphe(){/***/};
     
            Reference* insert_feuille(int); //
    };
     
    class Reference {//type struct
        public:
                Reference(Graphe* pt) : ref(pt) {/***/};
                Reference(const Reference& R) : ref(R.ref){/**copie**/};
                /*
                Reference operator=(const Reference& R){
                    if (this != &R) this->ref = R.ref;
                    return (*this);
                };
                */
     
                Graphe* ref; //pointeur du graphe
    };
     
    /************************************
    * la methode d'insertion de feuille *
    * qui crée une nouvelle référence   *
    ************************************/
    Reference* Graphe::insert_feuille(int n){
        feuilles.push_back(n);
        return new Reference(this);
    }
     
    struct delete_ptr
    {
        template <typename T>
        void operator()(T* pPtr)
        {
            delete pPtr;
        }
    };
     
     
    /************
    * le main   *
    ************/
     
    int main (int argc, char *argv[]) {
     
        //creation d'un vecteur de Graphe* et un vecteur de Reference*
        std::vector<Graphe*> vG;
        std::vector<Reference*> vR;
     
        //on remplie vG
        vG.push_back(new Graphe(NULL));
        //on met une refence dessus
        vR.push_back(new Reference(vG.back()));
     
        //test 1:
        std::cout << "1: " << vG.back() << " = " << vR.back()->ref << std::endl;
        std::cout << vR.front() << " taille :" << vR.size() <<std::endl;
     
        //avec l'utilisation d'iterator
        std::vector<Reference*>::iterator it = vR.begin();
     
        //on regarde l'iterateur
        std::cout << "it: " << *it << std::endl;
        //on met une nouvelle ref
        vR.push_back((*it)->ref->insert_feuille(53));
     
        //test 2:
        std::cout << "2: " << vG.back() << " = " << vR.back()->ref << std::endl;
        std::cout << vR.front() << " taille :" << vR.size() <<std::endl;
        std::cout << "it: " << *it << "<-- ouh la !" << std::endl;
     
        vR.push_back((*it)->ref->insert_feuille(53)); // forcement ça plante...
     
        //on efface
        std::for_each(vG.begin(), vG.end(), delete_ptr() );
        std::vector<Graphe*>().swap(vG);
     
        std::for_each(vR.begin(), vR.end(), delete_ptr() );
        std::vector<Reference*>().swap(vR);
     
        return EXIT_SUCCESS; //enfin...
    }
    je vois plus là...

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 176
    Points : 258
    Points
    258
    Par défaut
    Après un push_back les iterateurs peuvent être invalidés (dans le cas où ton vector doit être redimensionné).

    Donc, soit tu donnes à ton vector, d'emblée, assez d'espace pour ne pas avoir à être redimensionné (avec reserve()), soit, après le push_back tu remets ton iterateur dans un état valide (avec, par exemple, begin())

  3. #3
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Avril 2010
    Messages : 85
    Points : 61
    Points
    61
    Par défaut
    OK merci pour cette réponse rapide et limpide.

    Je ne connaissais pas cette propriété. J'était habitué à utiliser iterator comme un vulgaire pointeur.
    Ca va pas me réconcilier avec iterator tout ça...

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 176
    Points : 258
    Points
    258
    Par défaut
    un lien sur les règles d'invalidation des itérateurs en C++03 ici

    un lien sur les règles d'invalidation des itérateurs en C++11 ici

  5. #5
    Membre actif
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    176
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 176
    Points : 258
    Points
    258
    Par défaut
    Citation Envoyé par superZozo Voir le message
    Ca va pas me réconcilier avec iterator tout ça...
    Laisse leur une chance, une fois que tu les auras dompté, ils t'éviteront bien des soucis par rapport aux vulgaires index

  6. #6
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Avril 2010
    Messages : 85
    Points : 61
    Points
    61
    Par défaut
    OK merci pour toutes les infos.
    promis je vais essayer...

  7. #7
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Citation Envoyé par superZozo Voir le message
    Je ne connaissais pas cette propriété. J'était habitué à utiliser iterator comme un vulgaire pointeur.
    Ca va pas me réconcilier avec iterator tout ça...
    Raisonnement bizarre, car justement c'est parce qu’un un itérateur se comporte comme un pointeur qu'on observe ce comportement !

    En fait lors d'un push_back le vector peut décider de se redimensionner (si sa capacité est dépassée) , et il va le faire en allouant un nouveau bloc mémoire plus grand que l'ancien, puis en recopiant les éléments de l'ancien bloc mémoire au nouveau, et enfin en détruisant l'ancien bloc de mémoire.
    Donc tous les itérateurs existant avant le redimensionnement ont leur pointeur sous-jacent pointant maintenant vers une zone de mémoire invalide, d’où le seg fault.

  8. #8
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2010
    Messages
    85
    Détails du profil
    Informations personnelles :
    Localisation : France, Loiret (Centre)

    Informations forums :
    Inscription : Avril 2010
    Messages : 85
    Points : 61
    Points
    61
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Raisonnement bizarre, car justement c'est parce qu’un un itérateur se comporte comme un pointeur qu'on observe ce comportement !
    C'était une façon de parler. mal exprimé.
    J'ai fonctionné comme si l'iterator pouvait "suivre" le vector lors du redimensionnement (comme un index)(tout en étant un pointeur) (ahhhhhh !). C'est vrai que l'explication est simple et logique en fait.

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

Discussions similaires

  1. Qu'est-ce que je n'ai pas compris dans les threads ?
    Par Patrice Henrio dans le forum Concurrence et multi-thread
    Réponses: 25
    Dernier message: 27/01/2014, 11h56
  2. Example que je n'ai pas compris
    Par walid kh dans le forum VB.NET
    Réponses: 2
    Dernier message: 03/06/2010, 11h18
  3. Une chose que je ne comprend pas avec les editors/renderer
    Par Djobird dans le forum Composants
    Réponses: 6
    Dernier message: 30/03/2009, 10h24
  4. Quelques trucs que je ne comprends pas
    Par darkbob dans le forum Général JavaScript
    Réponses: 1
    Dernier message: 30/10/2006, 10h15
  5. [thread][methodologie]Quelque chose que je ne comprends pas!
    Par norkius dans le forum Général Java
    Réponses: 5
    Dernier message: 16/03/2005, 14h01

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