J'ai ce code:
int main()
{
vector<int> res;
res.Push_back(1);
vector<int>::iterator it = res.begin();
for( ; it != res.end(); it++)
{
it = res.erase(it);
//if(it == res.end())
// return 0;
}
}
"Un itérateur à accès aléatoire pointant vers le nouvel emplacement de l’élément qui suit le dernier élément effacé par l’appel de la fonction, qui est la fin du vecteur si l’opération efface le dernier élément de la séquence."
Ce code se bloque, mais si j'utilise le if (it == res.end ()), puis le retourne, cela fonctionne. Comment se fait-il? La boucle for encaisse-t-elle res.end () afin que l'opérateur non égal échoue?
res.erase(it)
renvoie toujours le prochain itérateur valide. Si vous effacez le dernier élément, il pointe sur .end()
.
À la fin de la boucle, ++it
est toujours appelé. Vous incrémentez donc .end()
, ce qui n'est pas autorisé.
La simple vérification de .end()
laisse toujours un bogue, car vous sautez toujours un élément à chaque itération (it
est 'incrémenté' par le retour de .erase()
, puis de nouveau par la boucle)
Vous voulez probablement quelque chose comme:
while (it != res.end()) {
it = res.erase(it);
}
effacer chaque élément
(Par souci d’exhaustivité: je suppose qu’il s’agit d’un exemple simplifié. Si vous souhaitez simplement que tous les éléments disparaissent sans qu’il soit nécessaire d’exécuter une opération dessus (par exemple, supprimez), vous devez simplement appeler res.clear()
).
Lorsque vous n’effacez que conditionnellement des éléments, vous voulez probablement quelque chose comme
for ( ; it != res.end(); ) {
if (condition) {
it = res.erase(it);
} else {
++it;
}
}
for( ; it != res.end();)
{
it = res.erase(it);
}
ou plus généralement:
for( ; it != res.end();)
{
if (smth)
it = res.erase(it);
else
++it;
}
Comme modification à la réponse de crazylammer, j'utilise souvent:
your_vector_type::iterator it;
for( it = res.start(); it != res.end();)
{
your_vector_type::iterator curr = it++;
if (something)
res.erase(curr);
}
L'avantage est que vous n'avez pas à craindre d'oublier d'incrémenter votre itérateur, ce qui le rend moins sujet aux bogues lorsque vous avez une logique complexe. Dans la boucle, curr ne sera jamais égal à res.end (), et ce sera au prochain élément, que vous l'effaciez ou non de votre vecteur.
Parce que la méthode erase in vector renvoie l'itérateur suivant de l'itérateur passé.
Je vais donner un exemple de la façon de supprimer un élément dans un vecteur lors d’une itération.
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 1
for(auto it = vecInt.begin();it != vecInt.end();){
if(*it % 2){// remove all the odds
it = vecInt.erase(it); // note it will = next(it) after erase
} else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 2
vecInt = {0, 1, 2, 3, 4, 5};
//method 2
for(auto it=std::begin(vecInt);it!=std::end(vecInt);){
if (*it % 2){
it = vecInt.erase(it);
}else{
++it;
}
}
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
// recreate vecInt, and use method 3
vecInt = {0, 1, 2, 3, 4, 5};
//method 3
vecInt.erase(std::remove_if(vecInt.begin(), vecInt.end(),
[](const int a){return a % 2;}),
vecInt.end());
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
sortie aw ci-dessous:
024
024
024
Une méthode plus générée:
template<class Container, class F>
void erase_where(Container& c, F&& f)
{
c.erase(std::remove_if(c.begin(), c.end(),std::forward<F>(f)),
c.end());
}
void test_del_vector(){
std::vector<int> vecInt{0, 1, 2, 3, 4, 5};
//method 4
auto is_odd = [](int x){return x % 2;};
erase_where(vecInt, is_odd);
// output all the remaining elements
for(auto const& it:vecInt)std::cout<<it;
std::cout<<std::endl;
}
Ne pas effacer puis incrémenter l'itérateur. Pas besoin d’augmenter, si votre vecteur a un nombre impair (ou même, je ne sais pas), vous manquerez la fin du vecteur.
if(allPlayers.empty() == false) {
for(int i = allPlayers.size() - 1; i >= 0; i--)
{
if(allPlayers.at(i).getpMoney() <= 0)
allPlayers.erase(allPlayers.at(i));
}
}
Cela fonctionne pour moi. Et vous n'avez pas besoin de penser aux index déjà effacés.
L'instruction it ++ est faite à la fin du bloc. Donc, si vous effacez le dernier élément, essayez d’incrémenter l’itérateur qui pointe vers une collection vide.
Vous incrémentez it
après la fin du conteneur (vide) dans l'expression de boucle de la boucle for.
Ce qui suit semble également fonctionner:
for (vector<int>::iterator it = res.begin(); it != res.end(); it++)
{
res.erase(it--);
}
Vous ne savez pas s'il y a une faille?