Est-ce que je peux enlever des éléments de std :: list, quand j'y vais?
Puis-je supprimer des éléments de std::list, quand je suis en itérant sur elle? Par exemple:
std::list<int> lst;
//....
for (std::list<int> itr = lst.begin(); itr != lst.end(); itr++)
{
if (*itr > 10)
lst.remove(*itr);
}
?
Et pourquoi?
source d'informationauteur Siarhei Fedartsou | 2010-11-23
Vous devez vous connecter pour publier un commentaire.
Le code correct est le suivant:
Lorsque vous supprimez un élément de la liste, vous pouvez invalider l'itérateur (si elle pointe vers le point d'être supprimé.) Par conséquent, vous devez supprimer à l'aide de
erase
(qui renvoie valide d'un itérateur pointant vers l'élément suivant).Bien meilleure idée serait d'utiliser
std::remove_if
:Si votre compilateur prend en charge les lambdasvous pouvez le mettre encore plus courte:
(Je n'ai pas testé ce code, que mon compilateur n'est pas si nouveau; la fonction lambda est heureusement volé @John Dibling de la réponse.)
En fait, l'effacement de la liste invalide uniquement les itérateurs pointant vers l'élément supprimé. Méfiez-vous cependant, que d'autres conteneurs STL n'ont pas cette propriété.
Donc, en résumé: d'une manière générale, vous ne devez pas supprimer les éléments de la liste lors de l'itération à travers elle, parce que la suppression peut invalider l'itérateur (et le programme va probablement se bloquer). Si vous êtes cependant tout à fait sûr que les articles que vous supprimez ne sont pas les valeurs référencées par les itérateurs que vous utilisez au moment de la suppression, vous pouvez la supprimer.
Méfiez-vous que pour les autres conteneurs STL (par exemple, les vecteurs) la contrainte est encore plus stricte: la suppression du conteneur invalide pas uniquement des itérateurs pointant vers l'élément supprimé, mais peut-être d'autres itérateurs, trop! Ainsi, la suppression de ce que les récipients lors de l'itération à travers eux, c'est encore plus problématique.
Pas. L'exemple de code invalide
itr
provoquant un comportement indéfini. Mais ce serait le travail:Non, vous ne pouvez pas.
Mais vous pouvez (et devez) utiliser
std::remove_if
avec un foncteur qui dit "plus de 10", comme ceci:Un autre, plus générique façon de le faire est d'écrire votre propre foncteur. Ici est un foncteur
is_a_match
qui renvoietrue
si la valeur en cours de vérification est supérieur à 10. Vous pouvez redéfiniroperator()
de retourtrue
pour correspondre à ce que cela signifie dans votre cas pour le "match":Si vous avez l'avantage de C++0x conforme compilateur, vous pouvez également utiliser les lambdas, qui permet de se débarrasser de l'foncteur et à écrire de plus expressive code dans de nombreux cas,
Je pense que vous pouvez, mais vous devez réaffecter l'itérateur après la suppression de l'élément, ce qui peut être fait avec
erase
plutôt la méthode queremove
.Sinon il va être dangereux et ne devrait pas être fait.
Voir http://www.cppreference.com/wiki/iterator/start pour une description des itérateurs.
Un couple de notes:
++itr
) au lieu de l'après-opérateur d'incrémentation (itr++
)