Безопасный способ непрерывного удаления из std :: vector? - PullRequest
2 голосов
/ 14 ноября 2010

Я думал, что следующий код будет работать, но он падает, когда целевой виджет находится в конце вектора.

for(std::vector<AguiWidget*>::iterator it = children.begin();
        it != children.end(); ++it)
    {
        if((*it) == widget)
            it = children.erase(it);
    }

Я хочу, чтобы он прошел и удалил любой найденный экземпляр виджета. Я понимаю, что этот метод N ^ 2, но так как это управляемый событиями, это хорошо. Я просто не знаю, почему это должно потерпеть неудачу. Когда это произойдет, 'это' == виджет.

Спасибо

Ответы [ 4 ]

7 голосов
/ 14 ноября 2010

Вы можете использовать идиому удаления-удаления, чтобы стереть все элементы, которые равны widget.

children.erase(remove(children.begin(), children.end(), widget), children.end());
2 голосов
/ 14 ноября 2010

Вам, вероятно, следует придерживаться списков, если вы хотите использовать такое удаление.Но проблема в том, что вы лишаете законной силы свой итератор, а затем пытаетесь увеличить его.Попробуйте вместо этого.

for(std::vector<AguiWidget*>::iterator it = children.begin();
    it != children.end();)
{
    if(*it == widget)
        children.erase(it++);
    else
        ++it;
}

Обратите внимание, что я не увеличиваю итератор внутри оператора for-loop.

0 голосов
/ 14 ноября 2010

Чтобы дополнить ответ Blastfurnace, вы также можете сделать это с помощью простого цикла for, если вы сделаете это в обратном направлении.

for (widgets::reverse_iterator it = children.rbegin(), end = children.rend();
     it != end; ++it)
{
  if (*it == widget) { children.erase(it.base()); }
}
0 голосов
/ 14 ноября 2010

Вы понимаете, что сравниваете указатели , а не разыменования, верно?

Можете ли вы сказать нам, что произойдет, если вы используете идиому удаления-стирания? Это будет быстро (не так, как ваш код) и правильно:

children.erase(std::remove_if(children.begin(), children.end(),
                              std::bind1st(std::equal_to<AguiWidget*>(),
                                           widget)));

Также не забудьте сначала удалить указатели.

for_each_if(children.begin(), children.end(),
            std::bind1st(std::equal_to<AguiWidget*>(), widget),
            Delete());

Конечно, вы должны быть уверены, что два указателя не указывают на один и тот же объект.

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