OVH Cloud OVH Cloud

STL et itérateurs

11 réponses
Avatar
Hamiral
Bonjour,

Je me suis remis très récemment au C++, et je me trouve avec un problème
d'itérateur que je n'arrive pas à résoudre. Il me semblait que ce serait
plutôt trivial, il s'agit de parcourir une std::list avec un itérateur,
dans une fonction operator=.
Le problème est le suivant : j'ai une classe Level et une classe Ball.
La classe Level contient la déclaration suivante (en protected) :
std::list<Ball> mBalls;

et voici mon operator= :
Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}

Je pensais que c'était comme cela qu'on utilise les itérateurs, mais le
compilateur me sort systématiquement l'erreur suivante :

level.cpp: Dans member function « Level& Level::operator=(const Level&) »:
level.cpp:7: error: no match for 'operator=' in 'iter = std::list<_Tp,
_Alloc>::begin() const [with _Tp = Ball, _Alloc =
std::allocator<Ball>]()'
/usr/include/c++/3.3/bits/stl_list.h:145: error: candidates are:
std::_List_iterator<Ball, Ball&, Ball*>& std::_List_iterator<Ball, Ball&,
Ball*>::operator=(const std::_List_iterator<Ball, Ball&, Ball*>&)


Je n'y comprends rien et ce malgré toute les recherches que j'ai pu
faire sur le net ...

Merci d'avance pour votre aide.

--
Hamiral

10 réponses

1 2
Avatar
Hamiral
level.cpp: Dans member function « Level& Level::operator=(const Level&) »:
level.cpp:7: error: no match for 'operator=' in 'iter = std::list<_Tp,
_Alloc>::begin() const [with _Tp = Ball, _Alloc > std::allocator<Ball>]()'
/usr/include/c++/3.3/bits/stl_list.h:145: error: candidates are:
std::_List_iterator<Ball, Ball&, Ball*>& std::_List_iterator<Ball, Ball&,
Ball*>::operator=(const std::_List_iterator<Ball, Ball&, Ball*>&)



J'ai oublié de préciser que la ligne 7 correspond à la ligne du for.
Merci encore.

Avatar
loic.actarus.joly

Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}


Pour itérer sur un conteneur constant, il te faut un const_iterator.

--
Loïc

Avatar
Falk Tannhäuser
Hamiral wrote:
Le problème est le suivant : j'ai une classe Level et une classe Ball.
La classe Level contient la déclaration suivante (en protected) :
std::list<Ball> mBalls;

et voici mon operator= :
Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}


Pourquoi pas tout simplement

Level& Level::operator=(Level const& level)
{
mBalls = level.mBalls;
return *this;
}

?

Falk

Avatar
Manuel Zaccaria
"Hamiral" a écrit:
Bonjour,



Bonjour,

Je me suis remis très récemment au C++, et je me trouve avec un problème
d'itérateur que je n'arrive pas à résoudre. Il me semblait que ce serait
plutôt trivial, il s'agit de parcourir une std::list avec un itérateur,
dans une fonction operator=.
Le problème est le suivant : j'ai une classe Level et une classe Ball.
La classe Level contient la déclaration suivante (en protected) :
std::list<Ball> mBalls;

et voici mon operator= :
Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}


Pour commencer, tous les conteneurs de la bibliothèque standard sans
exception ont une sémantique objet, c'est-à-dire qu'ils supportent
directement la copie (par opposition à un pointeur nu par exemple).

Au lieu de copier toute la liste à la main, on pourrait faire:

Level& Level::operator=(const Level & level) {
mBalls = level.mBalls;
}

Mais si mBalls est le seul membre donnée de la classe Level, ou plus
généralement si il n'y a que des membres qui sont copiables, il est
recommandé de laisser le compilateur générer le constructeur de copie
et l'opérateur d'affectation et de ne pas s'en soucier.

Grosso modo. J'espère que j'ai pas écris des conneries.

...


Cordialement,
Manuel

Avatar
Hamiral


Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}



Pour itérer sur un conteneur constant, il te faut un const_iterator.



Merci ! Mais comment est-ce que je fais pour savoir dans quel cas je me
trouve ?


Avatar
Hamiral
Pourquoi pas tout simplement

Level& Level::operator=(Level const& level)
{
mBalls = level.mBalls;
return *this;
}

?

Falk



Effectivement je ne me doutais pas de cette possibilité ...
J'avoue que je me suis un peu acharné sur les itérateurs /aussi/ pour
des raisons d'apprentissage.

--
Hamiral

Avatar
Vincent Lascaux
Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end();
++iter) {
mBalls.push_back(*iter);
}
}



Pour itérer sur un conteneur constant, il te faut un const_iterator.



Merci ! Mais comment est-ce que je fais pour savoir dans quel cas je me
trouve ?


level est const (cf le mot clé const dans const Level& level). Par
conséquent tous les membres non "mutable" de level sont accessible de façon
constante uniquement. C'est le cas de mBalls. Donc level.mBalls est un objet
constant et la méthode level.mBalls.begin retourne un const_iterator (qu'on
ne peut pas caster en iterator)

--
Vincent



Avatar
kanze
Hamiral wrote:

Level& Level::operator=(const Level & level) {
mBalls.clear();

std::list<Ball>::iterator iter;
for (iter = level.mBalls.begin(); iter != level.mBalls.end( );
++iter) {
mBalls.push_back(*iter);
}
}


Pour itérer sur un conteneur constant, il te faut un const_iterator.


Merci ! Mais comment est-ce que je fais pour savoir dans quel
cas je me trouve ?


Qu'importe. Si tu ne veux rien modifier, utilise un
const_iterator. Si l'objet n'est pas const, l'iterator que
renvoie begin() et end() se convertit implicitement en
const_iterator. (Si tu veux modifier quelque chose, évidemment,
tu utilises iterator. Si la collection est const, et que tu n'as
pas droit de la modifier, le compilateur te le dira.)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
kanze
Hamiral wrote:
Pourquoi pas tout simplement

Level& Level::operator=(Level const& level)
{
mBalls = level.mBalls;
return *this;
}

?


Effectivement je ne me doutais pas de cette possibilité ...
J'avoue que je me suis un peu acharné sur les itérateurs
/aussi/ pour des raisons d'apprentissage.


Mais alors, la solution serait :

mBalls.clear() ;
std::copy( level.mBalls.begin(), level.mBalls.end(),
std::back_inserter( mBalls ) ) ;

:-)

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Falk Tannhäuser
kanze wrote:
Hamiral wrote:
Effectivement je ne me doutais pas de cette possibilité ...
J'avoue que je me suis un peu acharné sur les itérateurs
/aussi/ pour des raisons d'apprentissage.


Mais alors, la solution serait :

mBalls.clear() ;
std::copy( level.mBalls.begin(), level.mBalls.end(),
std::back_inserter( mBalls ) ) ;


Voici encore d'autres possibilités :

mBalls.assign(level.mBalls.begin(), level.mBalls.end());

ou (un peu plus long)

mBalls.clear();
mBalls.insert(mBalls.end(), level.mBalls.begin(), level.mBalls.end());

Falk


1 2