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 Problème d'itérateur


Sujet :

SL & STL C++

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut STL Problème d'itérateur
    Bonjour à tous,

    Je travaille sur l'implémentation d'un projet en C++ et j'ai quelques soucis avec les iterateurs de STL (c'est la première fois que je rencontre ce genre de problème). Je l'expose.

    J'ai une classe virtuelle pure VirtClass et deux classes qui héritent de VirtClass : Class1 et Class2 !

    Ensuite, j'ai un vecteur de pointeur sur VirtClass qui contient les instances des deux classes Class1 et Class2 : vector<VirtClass*> vec;

    Lorsque je veux parcourir ce vecteur avec un iterator, impossible : la compilation se passe bien mais à l'exécution, j'ai un message d'erreur de Visual : vector iterators incompatible. Idem avec le const_iterator !

    Le pire dans tout ça, c'est que si je passe par une boucle for de i = 0 à vec.size(), ça fonctionne !!!

    Je souhaiterai comprendre pourquoi l'iterator ne fonctionne pas.
    Je vous remercie par avance.

  2. #2
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    ce que tu essaie de faire est parfaitement faisable. Il s'agit donc d'un problème dans ton code. Pourrais-tu nous le montrer?
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut
    Ok,

    Voici la déclaration de VirtClass :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class VirtClass 
    {
    protected:
    	int n;
     
    public:
    	virtual void extract() = 0;
    	int getN() const { return n; }
    };
    Voici la déclaration de Class1 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Class1 : public VirtClass
    {
    protected:
    	vector<string> strs;
     
    public:
    	Class1 () 
    	Class1 (VirtClass* v) { n = v->getN(); }
     
    	~Class1 () { }
     
    	void extract() { }
    };
    Et celle de Class2 :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class Class2 : public VirtClass
    {
    protected:
    	vector<OtherObj*> objs;
     
    public:
    	Class2 () 
    	Class2 (VirtClass* v) { n = v->getN(); }
     
    	~Class2 () { }
     
    	void extract() { }
    };
    Ces trois classes sont sérializées avec Boost !

  4. #4
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Je ne vois pas, désolé.
    Afin d'essayer de trouver le problème, j'ai testé le code suivant, avec le niveau max pour les warning, et ça fonctionne parfaitement, sans warning.
    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
    #include <iostream>
    #include <vector>
     
    using namespace std;
     
    class VirtClass 
    {
    protected:
    	int n;
     
    public:
    	virtual void extract() = 0;
    	int getN() const { return n; }
    };
     
    class Class1 : public VirtClass
    {
    public:
    	Class1() : VirtClass() { n = 0; }
    	void extract() { cout << "extract Class1" << endl; }
    };
     
    class Class2 : public VirtClass
    {
    public:
    	Class2() : VirtClass() { n = 0; }
    	void extract() {  cout << "extract Class2" << endl; }
    };
     
    int main(int argc, char* argv[])
    {
    	vector< VirtClass*> v;
    	for ( int i = 0; i < 20; ++i )
    		if ( i%2 == 0 )
    			v.push_back( new Class1 );
    		else
    			v.push_back( new Class2 );
     
    	for ( vector< VirtClass*>::iterator it = v.begin(); it != v.end(); ++it )
    		(*it)->extract();
     
    	// nep as oublier de détruire le contenu de v sinon ya une fuite mémoire là
    	for ( vector< VirtClass*>::iterator it = v.begin(); it != v.end(); ++it )
    		delete (*it);
     
    	cin.get();
    	return 0;
    }
    Donc je ne sais pas, c'est peut-être à cause* de boost::serialize, que je ne connais pas.


    * lire "à cause d'une mauvaise utilisation de"
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  5. #5
    Membre du Club
    Profil pro
    Inscrit en
    Octobre 2007
    Messages
    95
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut
    Ok, merci, alors, je viens d'utiliser le code fourni et ça fonctionne, je le confirme.

    Maintenant, j'ai apporté une petite modification : j'ai une classe Cont qui contient le vector<VirtClass*> vec;

    Si je mets vec en public et que j'utilise push_back pour ajouter des item, ça fonctionne. Mais dès que je le passe en private et en utilisant le getter et la méthode d'ajout, ça ne fonctionne plus :

    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
    class Cont
    {
    public:
    	vector<VirtClass*> vec;
     
    public:
    	Cont() {}
    	~Cont() {}
     
    public:	// Getters
    	vector<VirtClass*> getVec() const { return vec; }
     
    public: 
    	void addClass(VirtClass* c) { vec.push_back(c); }
    };
    Ensuite, dans le main, cc4 fonctionne et cc3 plante :

    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
     
    	Cont cc4;
    	cc4.vec.push_back(new Class1);
    	cc4.vec.push_back(new Class1);
    	cc4.vec.push_back(new Class2);
     
    	for(vector<VirtClass*>::iterator it = cc4.vec.begin(); it != cc4.vec.end(); ++it )
    		(*it)->extract();
     
     
    	Cont cc3;
    	cc3.addClass(new Class1);
    	cc3.addClass(new Class1);
    	cc3.addClass(new Class2);
     
    	for(vector<VirtClass*>::iterator it = cc3.getVec().begin(); it != cc3.getVec().end(); ++it )
    		(*it)->extract();
    Pourtant, il me semble que le getter est bon !!!

    [EDIT] : je n'utilise plus la serialization dans ces exemples !!

  6. #6
    Membre du Club
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    37
    Détails du profil
    Informations personnelles :
    Sexe : Homme

    Informations forums :
    Inscription : Septembre 2006
    Messages : 37
    Points : 64
    Points
    64
    Par défaut
    Citation Envoyé par Pg043 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public:	// Getters
    	vector<VirtClass*> getVec() const { return vec; }
    Le mot important est const.

    cc3 plante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
            // [...]
    	for(vector<VirtClass*>::iterator it = cc3.getVec().begin(); it != cc3.getVec().end(); ++it )
    		(*it)->extract();
    Le mot important devrait être const_iterator.

    Et comme extract() n'est pas const tu auras une erreur ;-).

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut
    Citation Envoyé par N i h i l Voir le message
    Le mot important est const.


    Le mot important devrait être const_iterator.

    Et comme extract() n'est pas const tu auras une erreur ;-).
    Merci, mais j'ai essayé d'utiliser un const_iterator et ça ne change rien !
    D'autant plus que l'erreur apparait avant l'appel à extract()

  8. #8
    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
    Bonjour,
    Citation Envoyé par N i h i l
    Le mot important est const.
    const n'est pas la cause du plantage.
    Citation Envoyé par Pg043 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<VirtClass*> getVec() const { return vec; }
    Pourtant, il me semble que le getter est bon !!!
    Non il n'est pas bon. Le problème c'est que le getter renvoie une copie de vec.
    Donc ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(vector<VirtClass*>::iterator it = cc3.getVec().begin(); it != cc3.getVec().end(); ++it )
    récupère l'itérateur begin et end sur deux copies temporaires de vec, copies qui ne sont plus valables ici :
    Un getter doit renvoyer une référence (constante ou non) sur la donnée membre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    const vector<VirtClass*>& getVec() const { return vec; }

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut
    Merci Arzar, il semble que cela fonctionne maintenant !

    Pour aller plus loin, si maintenant je veux utiliser un iterator pour parcourir et modifier mon vector, il suffit d'ajouter un deuxième getter comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<VirtClass*>& getVec() { return vec; }

  10. #10
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Arzar Voir le message
    Un getter doit renvoyer une référence (constante ou non) sur la donnée membre
    J'ai failli faire la même remarque, mais en fait je pense que ce n'est pas forcément systématique. Parfois on peut vouloir renvoyer une copie. Par exemple si on veut appliquer des algorithmes qui modifient la structure renvoyée, mais sans modifier la structure membre de la classe; typiquement pour faire des prédictions.
    Par contre dans ce cas, c'est sûr que le nom de la fonction serait plutôt GetCopy ou quelque chose dans le style, pour expliciter clairement que l'appelant reçoit une copie.

    Mais comme Pg043 ne nous dit rien, ni de ses intentions, ni de la ligne qui pose problème, ni de la nature de l'erreur, il est difficile de se prononcer.

    Et puis il y a bien d'autres problèmes. Par exemple, le fait que, lorsqu'un objet est destiné à être stocké dans un conteneur, il faut faire particulièrement attention aux constructeurs, or ici il n'y a pas ni de constructeur par copie ni d'opérateur d'assignation. Ou le fait, étrange, mais peut-être légitime (encore une fois, il est impossible de se prononcer vu le manque d'information) que la variable membre n de la classe mère soit initialisée par les classes filles.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

  11. #11
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    tech lead c++ linux
    Inscrit en
    Août 2004
    Messages
    4 262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : tech lead c++ linux

    Informations forums :
    Inscription : Août 2004
    Messages : 4 262
    Points : 6 680
    Points
    6 680
    Billets dans le blog
    2
    Par défaut
    Citation Envoyé par Pg043 Voir le message
    Merci Arzar, il semble que cela fonctionne maintenant !

    Pour aller plus loin, si maintenant je veux utiliser un iterator pour parcourir et modifier mon vector, il suffit d'ajouter un deuxième getter comme ceci ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    vector<VirtClass*>& getVec() { return vec; }
    Oui, mais ça casse l'encapsulation.
    Outre les problèmes de sécurité et de stabilité, lorsqu'on encapsule un conteneur dans une classe, c'est parce qu'on souhaite que ce soit cette classe qui gère ce conteneur. Si ce n'est pas le cas, le conteneur n'a rien à faire dans cette classe.
    « L'effort par lequel toute chose tend à persévérer dans son être n'est rien de plus que l'essence actuelle de cette chose. »
    Spinoza — Éthique III, Proposition VII

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

    Informations forums :
    Inscription : Octobre 2007
    Messages : 95
    Points : 62
    Points
    62
    Par défaut
    Ok ok r0d, merci de ton aide, et désolé pour le manque d'info !

    Et puis il y a bien d'autres problèmes. Par exemple, le fait que, lorsqu'un objet est destiné à être stocké dans un conteneur, il faut faire particulièrement attention aux constructeurs, or ici il n'y a pas ni de constructeur par copie ni d'opérateur d'assignation. Ou le fait, étrange, mais peut-être légitime (encore une fois, il est impossible de se prononcer vu le manque d'information) que la variable membre n de la classe mère soit initialisée par les classes filles.
    Ceci est bien géré !

    En fait, pour comprendre l'erreur, j'ai repris ces quelques classes dans un projet que je voulais le plus light possible !

    Mais comme Pg043 ne nous dit rien, ni de ses intentions, ni de la ligne qui pose problème, ni de la nature de l'erreur, il est difficile de se prononcer.
    Il me semble avoir décris le problème dans le premier post !

    En tout cas, merci beaucoup à tous pour votre aide.

Discussions similaires

  1. Problème d'itérateur et de vecteur
    Par befast dans le forum C++
    Réponses: 1
    Dernier message: 19/10/2006, 19h47
  2. STL : problème avec un iterateur
    Par fabienpot dans le forum SL & STL
    Réponses: 4
    Dernier message: 06/09/2006, 09h06
  3. [STL]Problème avec map
    Par mambo dans le forum SL & STL
    Réponses: 11
    Dernier message: 27/07/2006, 15h39
  4. [STL]Problème itérateur avec list
    Par Fiquet dans le forum SL & STL
    Réponses: 7
    Dernier message: 03/10/2005, 17h54
  5. conteneur de la STL (problème avec DLL et COM)
    Par moldavi dans le forum MFC
    Réponses: 8
    Dernier message: 25/07/2005, 22h43

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