J'ai un code qui ressemble à ceci:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
Je souhaite supprimer les éléments inactifs immédiatement après leur mise à jour, afin d'éviter de parcourir à nouveau la liste. Mais si j'ajoute les lignes commentées, j'obtiens une erreur lorsque j'arrive à i++
: "L'itérateur de liste n'est pas incrémentable". J'ai essayé des suppléants qui n'ont pas augmenté dans l'instruction for, mais je n'ai rien pu faire.
Quelle est la meilleure façon de supprimer des éléments lorsque vous parcourez une liste std ::?
Réponses:
Vous devez d'abord incrémenter l'itérateur (avec i ++) puis supprimer l'élément précédent (par exemple, en utilisant la valeur renvoyée par i ++). Vous pouvez changer le code en une boucle while comme ceci:
la source
i = items.erase(i)
est plus sûre, car elle est équivalente à une liste, mais fonctionnera toujours si quelqu'un change le conteneur en vecteur. Avec un vecteur, erase () déplace tout vers la gauche pour remplir le trou. Si vous essayez de supprimer le dernier élément avec du code qui incrémente l'itérateur après l'effacement, la fin se déplace vers la gauche et l'itérateur se déplace vers la droite - après la fin. Et puis vous vous plantez.Vous voulez faire:
Cela mettra correctement à jour l'itérateur pour pointer vers l'emplacement après l'itérateur que vous avez supprimé.
la source
i==items.begin()
?i= items.erase(i);
. C'est la forme canonique et s'occupe déjà de tous ces détails.Vous devez faire la combinaison de la réponse de Kristo et de MSN:
Bien sûr, la chose la plus efficace et la plus efficace de SuperCool® STL serait quelque chose comme ceci:
la source
Utilisez l'algorithme std :: remove_if.
Edit: Le travail avec les collections devrait ressembler à: 1. préparer la collection. 2. collecte de processus.
La vie sera plus facile si vous ne mélangez pas ces étapes.
la source
Voici un exemple utilisant une
for
boucle qui itère la liste et incrémente ou revalide l'itérateur en cas de suppression d'un élément pendant la traversée de la liste.la source
L'alternative pour la version en boucle à la réponse de Kristo.
Vous perdez de l'efficacité, vous revenez en arrière puis recommencez lors de la suppression, mais en échange de l'incrément d'itérateur supplémentaire, vous pouvez faire déclarer l'itérateur dans la portée de la boucle et le code un peu plus propre. Que choisir dépend des priorités du moment.
La réponse était totalement hors du temps, je sais ...
la source
iterator cannot be decremented
Laerase
méthode a besoin d'unrandom access iterator
. Certaines implémentations de collection fournissent unforward only iterator
qui provoque l'assertion.Je l'ai résumé, voici les trois méthodes avec exemple:
1. en utilisant la
while
boucle2. en utilisant la fonction
remove_if
membre dans la liste:3. en utilisant la fonction
std::remove_if
combinée avec laerase
fonction membre:4. en utilisant la
for
boucle, notez la mise à jour de l'itérateur:la source
La suppression invalide uniquement les itérateurs qui pointent vers les éléments qui sont supprimés.
Donc, dans ce cas, après avoir supprimé * i, i est invalidé et vous ne pouvez pas l'incrémenter.
Ce que vous pouvez faire, c'est d'abord enregistrer l'itérateur de l'élément à supprimer, puis incrémenter l'itérateur, puis supprimer celui enregistré.
la source
Si vous pensez
std::list
à une file d'attente, vous pouvez retirer et mettre en file d'attente tous les éléments que vous souhaitez conserver, mais uniquement retirer (et non mettre en file d'attente) l'élément que vous souhaitez supprimer. Voici un exemple où je veux supprimer 5 d'une liste contenant les numéros 1-10 ...myList
aura désormais uniquement les numéros 1-4 et 6-10.la source
L'itération vers l'arrière évite d'effacer un élément sur les autres éléments à parcourir:
PS: voyez ceci , par exemple, concernant l'itération en arrière.
PS2: Je n'ai pas testé à fond s'il gère bien les éléments effaçables aux extrémités.
la source
avoids the effect of erasing an element on the remaining elements
pour une liste, probablement oui. Pour un vecteur peut-être pas. Ce n'est pas quelque chose de garanti sur les collections arbitraires. Par exemple, une carte peut décider de se rééquilibrer.Tu peux écrire
Vous pouvez écrire du code équivalent avec
std::list::remove_if
, qui est moins détaillé et plus explicitele
std::vector::erase
std::remove_if
idiome doit être utilisé lorsque les éléments sont un vecteur au lieu d'une liste pour conserver la compexité à O (n) - ou si vous écrivez du code générique et que les éléments peuvent être un conteneur sans moyen efficace d'effacer des éléments uniques (comme un vecteur)la source
Je pense que vous avez un bug, je code de cette façon:
la source