tags:

views:

98

answers:

1

The proper way to iterate is to use iterators. However, I think by erasing, the iterator is invalidated.

Basically what I want to do is:

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

}

How could I do this without v[i] method?

Thanks

struct RemoveTimedEvent
{
    bool operator()(const AguiTimedEvent& pX, AguiWidgetBase* widget) const 
    {
        return pX.getCaller() == widget;
    }
};

void AguiWidgetContainer::clearTimedEvents( AguiWidgetBase* widget )
{
    std::vector<AguiTimedEvent>::iterator it = std::remove_if(timedEvents.begin(),
        timedEvents.end(), RemoveTimedEvent());
    timedEvents.erase(it, timedEvents.end());

}
+10  A: 

erase() returns a new iterator:

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

A better method might be to combine std::remove_if and erase(). You change from being O(N2) (every element gets erased) to O(N):

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

Where pred is you predicate, such as:

struct predicate // do choose a better name
{
    bool operator()(const T& pX) const // replace T with your type
    {
        return pX.somecondition();
    }
};

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

In your case, you can make it pretty general:

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

    // if every thing that has getCaller has a base, use that instead
    template <typename T> // for now a template
    bool operator()(const T& 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());

Note lambda's exist to simplify this process, both in Boost and C++0x.

GMan
Oh great thanks! +1:)
Milo
I'm not sure I understand how the first method is N squared, why is it not N, I only iterate through once to remove the items.
Milo
Unless ofcourse the iterator returned by erase brings you back to the top
Milo
The problem with that is the condition is dependent on an argument of a function passed to the erase function
Milo
@Milo: It's N^2. If you erase the first element, all the other elements will be copied down to take it's place. Do that N times and you've touched each one N^2 times. You can pass the argument to the predicate, which forwards it.
GMan
@GMan, I'm still not sure how I can pass an additional argument to the () operator. see my edit:
Milo
@Milo: Alright, see mine.
GMan
@GMan awesome thanks!
Milo
@Milo: No probs.
GMan