OVH Cloud OVH Cloud

vector::iterator et NULL

7 réponses
Avatar
Toto Le Ouf
Bonjour, j'ai un petit problème :

je déclare des itérateurs ainsi (Student et Semestre sont des classes
définies correctement, normalement...) :
vector<Student>::iterator i ;
list<Semestre>::iterator j ;

je les initialise :
i = NULL;
j = NULL;

et voici le résultat du compilo :
102 D:\XXX\Mini-Projet\ZZZ\test.cpp no match for 'operator=' in 'i = 0'

Une idée ? Pourquoi cela fonctionne-t-il avec list<> et non avec vector<> ?
Merci.
T.

7 réponses

Avatar
Falk Tannhäuser
Toto Le Ouf wrote:

je déclare des itérateurs ainsi (Student et Semestre sont des classes
définies correctement, normalement...) :
vector<Student>::iterator i ;
list<Semestre>::iterator j ;

je les initialise :
i = NULL;
j = NULL;


Dans quel but ? Qu'est-ce que cela devrait donner d'après toi ?
D'habitude, on ne déclare et initialise les itérateurs que lorsqu'on
sait avec quoi :
std::vector<Student>::iterator i = std::find(AllStudents.begin(),
AllStudents.end(),
Student("Toto Le Ouf"));

for(std::list<Semestre>::iterator j = AllSemesters.begin();
j != AllSemesters.end();
++j)
{
// ...
}

et voici le résultat du compilo :
102 D:XXXMini-ProjetZZZtest.cpp no match for 'operator=' in 'i = 0'

Une idée ? Pourquoi cela fonctionne-t-il avec list<> et non avec vector<> ?


La Norme ne prévoit pas que l'on puisse affecter 0 à un itérateur -
les itérateurs ne sont pas des pointeurs même s'ils y ressemblent.
Il se peut que cela compile sur certaines implémentations, surtout
avec 'std::vector<toto>::iterator' car parfois celui-ci est simplement
un typedef pour 'toto*' - mais ce n'est pas vrai partout, donc il ne
faut pas compter la dessus.

Autre question: Es-tu sûr que les classes 'Student' et 'Semestre' doivent
avoir une sémantique de valeur, c.a.d. si des étudiants et semestres doivent
être librement copiables ? Cela voudrait dire que tu auras probablement
plusieurs copies (instances) d'un même étudiant dans ton programme, et
une mise à jour des attributs d'une instance (cours auxquels il participe,
notes etc.) ne se répercutera pas sur les autres instances. Cela me semble
bizarre...
Tu veux peut-être plutôt
std::vector<Student*>
ou
std::vector<boost::shared_ptr<Student> >
à la place de
std::vector<Student>
puis rendre le constructeur de copie et l'affectation 'private' (et sans
implémentation) dans la classe 'Student', de manière à lui donner une
sémantique de référence (c.a.d. pour chaque étudiant, il n'existera qu'une
instance le représentant dans le programme, qui sera manipulée par des
références ou pointeurs) ?

Falk

Avatar
Falk Tannhäuser
Toto Le Ouf wrote:

je déclare des itérateurs ainsi (Student et Semestre sont des classes
définies correctement, normalement...) :
vector<Student>::iterator i ;
list<Semestre>::iterator j ;

je les initialise :
i = NULL;
j = NULL;



Dans quel but ? Qu'est-ce que cela devrait donner d'après toi ?
D'habitude, on ne déclare et initialise les itérateurs que lorsqu'on
sait avec quoi :
std::vector<Student>::iterator i = std::find(AllStudents.begin(),
AllStudents.end(),
Student("Toto Le Ouf"));

for(std::list<Semestre>::iterator j = AllSemesters.begin();
j != AllSemesters.end();
++j)
{
// ...
}

et voici le résultat du compilo :
102 D:XXXMini-ProjetZZZtest.cpp no match for 'operator=' in 'i = 0'

Une idée ? Pourquoi cela fonctionne-t-il avec list<> et non avec vector<> ?



La Norme ne prévoit pas que l'on puisse affecter 0 à un itérateur -
les itérateurs ne sont pas des pointeurs même s'ils y ressemblent.
Il se peut que cela compile sur certaines implémentations, surtout
avec 'std::vector<toto>::iterator' car parfois celui-ci est simplement
un typedef pour 'toto*' - mais ce n'est pas vrai partout, donc il ne
faut pas compter là-dessus.

Autre question: Es-tu sûr que les classes 'Student' et 'Semestre' doivent
avoir une sémantique de valeur, c.a.d. si des étudiants et semestres doivent
être librement copiables ? Cela voudrait dire que tu auras probablement
plusieurs copies (instances) d'un même étudiant dans ton programme, et
une mise à jour des attributs d'une instance (cours auxquels il participe,
notes etc.) ne se répercutera pas sur les autres instances. Cela me semble
bizarre...
Tu veux peut-être plutôt
std::vector<Student*>
ou
std::vector<boost::shared_ptr<Student> >
à la place de
std::vector<Student>
puis rendre le constructeur de copie et l'affectation 'private' (et sans
implémentation) dans la classe 'Student', de manière à lui donner une
sémantique de référence (c.a.d. pour chaque étudiant, il n'existera qu'une
instance le représentant dans le programme, qui sera manipulée par des
références ou pointeurs) ?

Falk

Avatar
Toto Le Ouf
Dans quel but ? Qu'est-ce que cela devrait donner d'après toi ?
D'habitude, on ne déclare et initialise les itérateurs que lorsqu'on
sait avec quoi :
std::vector<Student>::iterator i = std::find(AllStudents.begin(),
AllStudents.end(),
Student("Toto Le Ouf"));

for(std::list<Semestre>::iterator j = AllSemesters.begin();
j != AllSemesters.end();
++j)
{
// ...
}
La Norme ne prévoit pas que l'on puisse affecter 0 à un itérateur -
les itérateurs ne sont pas des pointeurs même s'ils y ressemblent.
Il se peut que cela compile sur certaines implémentations, surtout
avec 'std::vector<toto>::iterator' car parfois celui-ci est simplement
un typedef pour 'toto*' - mais ce n'est pas vrai partout, donc il ne
faut pas compter là-dessus.


En réalité, j'ai un vecteur d'étudiant (vector<Student> _vecteur) et un
itérateur sur celui ci (vector<Student>::iterator i) qui représente
l'étudiant courant
J'ai une fonction qui me permet de supprimer l'étudiant courant du vecteur
(elle utilise _vecteur.erase(i) ) et à chaque fois que j'utilise cette
fonction, je décrémente l'itérateur i. Donc, quand je vais supprimer le
dernier étudiant, i sera décrémenté et ne pointera plus sur rien, d'où une
erreur d'execution quand j'essaierai de supprimer encore un étudiant.
A part, regarder si la taille du vecteur n'est pas de 0, n'y a-t-il pas une
autre solution ?
Merci.
T.

Avatar
Richard Delorme

En réalité, j'ai un vecteur d'étudiant (vector<Student> _vecteur) et un
itérateur sur celui ci (vector<Student>::iterator i) qui représente
l'étudiant courant
J'ai une fonction qui me permet de supprimer l'étudiant courant du vecteur
(elle utilise _vecteur.erase(i) ) et à chaque fois que j'utilise cette
fonction, je décrémente l'itérateur i. Donc, quand je vais supprimer le
dernier étudiant, i sera décrémenté et ne pointera plus sur rien, d'où une
erreur d'execution quand j'essaierai de supprimer encore un étudiant.
A part, regarder si la taille du vecteur n'est pas de 0, n'y a-t-il pas une
autre solution ?


un reverse_iterator ?

--
Richard

Avatar
Arnaud Debaene
Toto Le Ouf wrote:

J'ai une fonction qui me permet de supprimer l'étudiant courant du
vecteur (elle utilise _vecteur.erase(i) ) et à chaque fois que
j'utilise cette fonction, je décrémente l'itérateur i.
C'est là qu'est ton erreur : vector.erase invalide l'itérateur qui lui est

passé, donc tu ne peux plus rien faire de cet itérateur, même pas
l'incrémenter ou le décrémenter. Par contre, vector.erase renvoie un autre
itérateur sur l'objet suivant dans le vector (ou sur end) : c'st lui que tu
dois utiliser pour poursuivre ton itération sur le vecteur.

Arnaud

Avatar
Toto Le Ouf
C'est là qu'est ton erreur : vector.erase invalide l'itérateur qui lui est
passé, donc tu ne peux plus rien faire de cet itérateur, même pas
l'incrémenter ou le décrémenter. Par contre, vector.erase renvoie un autre
itérateur sur l'objet suivant dans le vector (ou sur end) : c'st lui que
tu

dois utiliser pour poursuivre ton itération sur le vecteur.


Ok, mais que se passe-t-il quand on supprime le dernier élément du vecteur :
que renvoie la fonction ? un itérateur ? Si oui, sur quoi ?
Merci.
T.

Avatar
Fabien LE LEZ
On Sun, 12 Jun 2005 14:52:29 +0200, thomas.carpentier :

Ok, mais que se passe-t-il quand on supprime le dernier élément du vecteur :
que renvoie la fonction ? un itérateur ? Si oui, sur quoi ?


Arnaud t'a déjà répondu :
Par contre, vector.erase renvoie un autre
itérateur sur l'objet suivant dans le vector (ou sur end)


Note que la fonction vector<>::erase() renvoie forcément un iterateur,
puisque c'est son type de retour. Et si le vector<> est vide, le seul
itérateur qui puisse être renvoyé est end().