Стирание из std :: vector при выполнении a для каждого? - PullRequest
24 голосов
/ 15 октября 2010

Правильный способ итерации - использовать итераторы. Тем не менее, я думаю, что при удалении итератор становится недействительным.

В основном я хочу сделать следующее:

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

}

Как я могу сделать это без метода v [i]?

Спасибо

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

}

1 Ответ

43 голосов
/ 15 октября 2010

erase() возвращает новый итератор:

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

Обратите внимание, что мы больше не можем сравнивать его с предварительно вычисленным концом, потому что мы можем стереть его и, следовательно, сделать его недействительным.Каждый раз мы должны получать конечный результат явно.

Лучшим способом может быть объединение std::remove_if и erase().Вы изменяете значение O (N 2 ) (каждый элемент стирается и перемещается по мере движения) на O (N):

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

Где pred - это предикат удаления,например:

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

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

В вашем случае вы можете сделать это довольно общим:

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

Обратите внимание, что лямбды существуют для упрощения этого процесса, как в Boost, так и в C ++ 11.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...