Maison > développement back-end > C++ > Comment effacer en toute sécurité des éléments d'un std :: vector pendant une itération avec une boucle For basée sur une plage ?

Comment effacer en toute sécurité des éléments d'un std :: vector pendant une itération avec une boucle For basée sur une plage ?

Susan Sarandon
Libérer: 2024-11-03 17:09:03
original
935 Les gens l'ont consulté

How to Safely Erase Elements from a std::vector During Iteration with a Range-Based For Loop?

Effacer des éléments d'un std :: vecteur lors d'une itération avec une boucle For basée sur une plage

Itérer sur un std :: vecteur et supprimer les éléments correspondant à une certaine condition peuvent être une tâche courante en programmation. Cependant, la syntaxe standard de la boucle For basée sur une plage présente un défi, car tenter d'effacer un élément lors d'une itération peut invalider l'itérateur.

Le problème de l'effacement dans une boucle For basée sur une plage

L'extrait de code suivant illustre le problème :

for(iterator it = begin; it != end; ++it)
{
    if(it->somecondition() )
    {
     erase it
    }

}
Copier après la connexion

Bien que l'intention soit de supprimer les éléments répondant à la condition, cette approche est incorrecte. Lorsqu'un élément est effacé, l'itérateur devient invalide. Continuer à itérer avec cet itérateur conduit à un comportement indéfini.

Solution 1 : Utiliser une boucle For régulière avec manipulation explicite de l'itérateur

Une solution consiste à utiliser une boucle for régulière avec manipulation explicite de l'itérateur :

for(iterator it = begin; it != end(container) /* !!! */;)
{
    if (it->somecondition())
    {
        it = vec.erase(it);  // Returns the new iterator to continue from.
    }
    else
    {
        ++it;
    }
}
Copier après la connexion

Notez ici la différence cruciale : nous appelons explicitement end(container) à chaque itération pour obtenir un nouvel itérateur de fin. Ceci est nécessaire car l'effacement d'un élément invalide l'itérateur d'origine.

Solution 2 : Utiliser std::remove_if et effacer

Une alternative plus efficace consiste à combiner std:: Remove_if et Eraser():

iterator it = std::remove_if(begin, end, pred);
vec.erase(it, vec.end());
Copier après la connexion

std::remove_if supprime les éléments correspondant à un prédicat spécifié, tandis que Eraser() les supprime. Cette approche réduit la complexité temporelle de O(N) à partir de O(N2) dans la première solution.

Solution spécifique à l'exemple fourni

Dans l'exemple spécifique donné, le code suivant peut être utilisé pour supprimer les événements chronométrés associés à un widget particulier :

class remove_by_caller
{
public:
    remove_by_caller(AguiWidgetBase* pWidget) :
    mWidget(pWidget)
    {}

    template <typename T> // for now a template
    bool operator()(const T&amp; pX) const
    {
        return pX.getCaller() == mWidget;
    }

private:
    AguiWidgetBase* mWidget;
};

std::vector<AguiTimedEvent>::iterator it =
    std::remove_if(timedEvents.begin(), timedEvents.end(), remove_by_caller(widget));
timedEvents.erase(it, timedEvents.end());
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal