OVH Cloud OVH Cloud

Vector et erase

15 réponses
Avatar
Michaël Delva
Bonjour à tous,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un élément
de ce vecteur doit être supprimé, est-ce que faire un erase() de
l'itérateur correspondant va affecter la suite de ma boucle? Ex:

for (std::vector<int>::const_iterator ite = vect.begin(); ite !=
vect.end(); ++ite)
if (*ite == 8)
vect.erase(*ite);

Après le erase(*ite), est-ce que c'est bien l'élément "après" qui va être
analysé?

J'espère m'être bien fait comprendre...

Merci d'avance

10 réponses

1 2
Avatar
Nicolas
ca dépend de l'implementation et du type d'objet pointé par l'iterateur.

il faut voir si dans l'implementation du vector<> (dans le man) le fait
d'effacer un element invalide l'iterateur.

en général, oui.
en gros:
v.erase(*iter);
*iter = 10; ca plante !

pour eviter ce genre de question, il faut préparer une iteration +1 :

ci = v.begin();
cn = ci++;
if (*ci == val)
v.erase(*ci);
ci = cn;
else
ci = cn;
cn++;
...

et la c'est clair ? ;-)
Avatar
Franck Branjonneau
"Michaël Delva" écrivait:

Bonjour à tous,


Bonjour,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un
élément de ce vecteur doit être supprimé, est-ce que faire un
erase() de l'itérateur correspondant va affecter la suite de ma
boucle?


Sans aucun doute. vector<>::erase(it) détruis l'élément désigné par it
et retourne un itérateur sur l'élément qui suivait it avant sa
destruction.

J'espère m'être bien fait comprendre...


Très bien.
--
Franck Branjonneau

Avatar
Fabien LE LEZ
On Mon, 23 Feb 2004 12:14:07 +0100, Nicolas
wrote:

il faut voir si dans l'implementation du vector<> (dans le man) le fait
d'effacer un element invalide l'iterateur.


Je confirme que c'est oui : une modification du nombre d'éléments d'un
std::vector<> invalide[*] tous les itérateurs sur des éléments de ce
vector<>. Ta solution ne fonctionne donc pas non plus.


[*] Plus précisément, on n'est pas sûr qu'ils sont invalidés, mais
comme la possibilité existe, on ne peut pas prendre le risque.

--
;-)

Avatar
Guillaume Brocker
Franck Branjonneau wrote:

Sans aucun doute. vector<>::erase(it) détruis l'élément désigné par it
et retourne un itérateur sur l'élément qui suivait it avant sa
destruction.


Pour revenir à l'exemple de départ, on peut le transfomer comme suit:

std::vector<int>::iterator ite = vect.begin();

for(;;)
{
if( ite != vect.end() )
{
if( *ite != 8 )
{
ite = vect.erase( ite );
}
else
{
ite++;
}
}
else
{
break;
}
}

--
Guillaume Brocker

Avatar
Jean-Marc Bourguet
Guillaume Brocker writes:

Franck Branjonneau wrote:

Sans aucun doute. vector<>::erase(it) détruis l'élément désigné par it
et retourne un itérateur sur l'élément qui suivait it avant sa
destruction.


Pour revenir à l'exemple de départ, on peut le transfomer comme suit:

std::vector<int>::iterator ite = vect.begin();

for(;;)
{
if( ite != vect.end() )
{
if( *ite != 8 )
{
ite = vect.erase( ite );
}
else
{
ite++;
}
}
else
{
break;
}
}


Et pourquoi ne pas utiliser un while plutot que la structure etrange

for(;;) {
if (cond) {
...
} else {
break;
}

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Manuel
"Michaël Delva" a écrit dans le message de
news:
Bonjour à tous,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un élément
de ce vecteur doit être supprimé, est-ce que faire un erase() de
l'itérateur correspondant va affecter la suite de ma boucle? Ex:

for (std::vector<int>::const_iterator ite = vect.begin(); ite ! > vect.end(); ++ite)
if (*ite == 8)
vect.erase(*ite);

Après le erase(*ite), est-ce que c'est bien l'élément "après" qui va être
analysé?

J'espère m'être bien fait comprendre...

Merci d'avance


Ca ne marchera pas comme ça.
L'itérateur n'est plus valide après vect.erase().

AMHA, ce serait mieux d'écrire :

std::vector<int>::const_iterator ite = vect.begin();
while (ite != vect.end())
if (*ite == 8)
vect.erase(*ite++);

Mais je n'en suis pas certain.
Une meilleure solution serait d'utiliser std::remove_if :

inline bool egale_huit(int n) { return (8 == n); }
// ou avec un template, un objet fonction, ... c'est selon le besoin.
vect.erase(std::remove_if(vect.begin(), vect.end(), egale_huit),
vect.end());

En espérant que ça aidera. :-)

--

- Manuel
to reply, swap the name with the domain.

Avatar
Franck Branjonneau
Jean-Marc Bourguet écrivait:

Guillaume Brocker writes:

Franck Branjonneau wrote:

Sans aucun doute. vector<>::erase(it) détruis l'élément désigné
par it et retourne un itérateur sur l'élément qui suivait it
avant sa destruction.


Pour revenir à l'exemple de départ, on peut le transfomer comme
suit:

[ une horrible boucle for ]


Et pourquoi ne pas utiliser un while plutot que la structure etrange

for(;;) {
if (cond) {
...
} else {
break;
}


Ou alors :

vect.erase(std::remove_if(vect.begin(), vect.end(),
std::bind2nd(std::equal_to< int >(), 5)), vect.end());
--
Franck Branjonneau



Avatar
Alain Migeon
In article ,
says...
Bonjour à tous,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un él ément
de ce vecteur doit être supprimé, est-ce que faire un erase() de
l'itérateur correspondant va affecter la suite de ma boucle? Ex:

for (std::vector<int>::const_iterator ite = vect.begin(); ite !=
vect.end(); ++ite)
if (*ite == 8)
vect.erase(*ite);

Après le erase(*ite), est-ce que c'est bien l'élément "après" qui va être
analysé?

J'espère m'être bien fait comprendre...

Merci d'avance


Une solution sûre consiste à mettre les itérateurs des éléments q ue tu
veux supprimer dans un autre vecteur. Et ensuite de parcourir ce
vecteur.

Alain

Exemple :


#include <vector>
using std::vector;

typedef std::vector <int> VInt;
typedef std::vector <VInt::iterator> VItInt;

int main ()
{
VInt vInt;
VInt::iterator itInt;

VItInt vItInt;
VItInt::iterator itItInt;

// ...
// remplissage de vInt.
// ...

for (itInt = vInt.begin (); itInt != vInt.end (); ++ itInt)
{
if (*itInt == 8)
vItInt.push_back (itInt);
}

for (itItInt = vItInt.begin (); itItInt != vItInt.end (); ++ itItInt )
vInt.erase (*itItInt);

vItInt.clear ();
}

Avatar
Jean-Marc Bourguet
Alain Migeon writes:

In article ,
says...
Bonjour à tous,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un élément
de ce vecteur doit être supprimé, est-ce que faire un erase() de
l'itérateur correspondant va affecter la suite de ma boucle? Ex:

for (std::vector<int>::const_iterator ite = vect.begin(); ite ! > > vect.end(); ++ite)
if (*ite == 8)
vect.erase(*ite);

Après le erase(*ite), est-ce que c'est bien l'élément "après" qui va être
analysé?

J'espère m'être bien fait comprendre...

Merci d'avance


Une solution sûre consiste à mettre les itérateurs des éléments que tu
veux supprimer dans un autre vecteur. Et ensuite de parcourir ce
vecteur.



Alain

Exemple :


#include <vector>
using std::vector;

typedef std::vector <int> VInt;
typedef std::vector <VInt::iterator> VItInt;

int main ()
{
VInt vInt;
VInt::iterator itInt;

VItInt vItInt;
VItInt::iterator itItInt;

// ...
// remplissage de vInt.
// ...

for (itInt = vInt.begin (); itInt != vInt.end (); ++ itInt)
{
if (*itInt == 8)
vItInt.push_back (itInt);
}

for (itItInt = vItInt.begin (); itItInt != vItInt.end (); ++ itItInt)
vInt.erase (*itItInt);

vItInt.clear ();
}



Pas sur du tout tel qu'ecrit: les iterateurs d'un vecteur (pointant
apres l'iterateur) sont invalides apres tout effacement. Si t'iteres
a l'envers par contre, c'est correct.

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org


Avatar
Alain Migeon
In article , says...
Alain Migeon writes:

In article ,
says...
Bonjour à tous,

quand je parcours un vecteur à l'aide d'une boucle for, et qu'un élément
de ce vecteur doit être supprimé, est-ce que faire un erase() de
l'itérateur correspondant va affecter la suite de ma boucle? Ex:

for (std::vector<int>::const_iterator ite = vect.begin(); ite !=
vect.end(); ++ite)
if (*ite == 8)
vect.erase(*ite);

Après le erase(*ite), est-ce que c'est bien l'élément "après" qui va être
analysé?

J'espère m'être bien fait comprendre...

Merci d'avance


Une solution sûre consiste à mettre les itérateurs des élémen ts que tu
veux supprimer dans un autre vecteur. Et ensuite de parcourir ce
vecteur.



Alain

Exemple :


#include <vector>
using std::vector;

typedef std::vector <int> VInt;
typedef std::vector <VInt::iterator> VItInt;

int main ()
{
VInt vInt;
VInt::iterator itInt;

VItInt vItInt;
VItInt::iterator itItInt;

// ...
// remplissage de vInt.
// ...

for (itInt = vInt.begin (); itInt != vInt.end (); ++ itInt)
{
if (*itInt == 8)
vItInt.push_back (itInt);
}

for (itItInt = vItInt.begin (); itItInt != vItInt.end (); ++ itI tInt)
vInt.erase (*itItInt);

vItInt.clear ();
}



Pas sur du tout tel qu'ecrit: les iterateurs d'un vecteur (pointant
apres l'iterateur) sont invalides apres tout effacement. Si t'iteres
a l'envers par contre, c'est correct.


Mea culpa.

J'ai écrit trop vite.
C'est la méthode que j'utilise pour supprimer les éléments d'un map.
Dans ce cas un itérateur reste valide jusqu'à sa suppression.

Alain



1 2