Home >Backend Development >C++ >How to Safely Erase Elements from a std::vector During Iteration with a Range-Based For Loop?

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

Susan Sarandon
Susan SarandonOriginal
2024-11-03 17:09:03928browse

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

Erasing Elements from a std::vector While Iterating with a Range-Based For Loop

Iterating over a std::vector and removing elements matching a certain condition can be a common task in programming. However, the standard range-based for loop syntax presents a challenge, as attempting to erase an element while iterating can invalidate the iterator.

The Problem with Erasing Within a Range-based For Loop

The following code snippet demonstrates the issue:

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

}

While the intention is to remove elements meeting the condition, this approach is incorrect. When an element is erased, the iterator becomes invalid. Continuing to iterate with that iterator leads to undefined behavior.

Solution 1: Using a Regular For Loop with Explicit Iterator Manipulation

One solution is to use a regular for loop with explicit iterator manipulation:

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

Note the crucial difference here: we explicitly call end(container) on each iteration to obtain a new end iterator. This is necessary because erasing an element invalidates the original iterator.

Solution 2: Using std::remove_if and erase

A more efficient alternative is to combine std::remove_if and erase():

iterator it = std::remove_if(begin, end, pred);
vec.erase(it, vec.end());

std::remove_if removes elements matching a specified predicate, while erase() deletes them. This approach reduces the time complexity to O(N) from O(N2) in the first solution.

Solution Specific to the Provided Example

In the specific example given, the following code can be used to remove timed events associated with a particular widget:

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

The above is the detailed content of How to Safely Erase Elements from a std::vector During Iteration with a Range-Based For Loop?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn