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
Susan Sarandonoriginal
2024-11-03 17:09:03962parcourir

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
    }

}

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;
    }
}

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());

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());

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!

Déclaration:
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