从std :: vector中删除,同时为每个? [英] Erasing from a std::vector while doing a for each?

查看:157
本文介绍了从std :: vector中删除,同时为每个?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

迭代的正确方法是使用迭代器。然而,我认为通过擦除,迭代器是无效的。



基本上我想做的是:

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

}

感谢

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

}


解决方案

erase()返回一个新的迭代器:

  for(iterator it = begin; it!= end(container)/ * !!! * /;)
{
if(it-> somecondition())
{
it = vec.erase它); //返回新的迭代器继续。
}
else
{
++ it;
}
}

请注意,我们无法再将其与预先计算的结束,因为我们可能会擦除它,因此使它无效。



一个更好的方法可能是结合 std :: remove_if code> erase()。您从O(N 2 )变为O(N):

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

其中 pred 是您的移除谓词as:

  struct predicate //做一个更好的名字
{
bool operator T& pX)const //用你的类型替换T
{
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)
{}

//如果每一个有getCaller的东西都有一个基础,那么使用
template< typename T> //现在为模板
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());

注意lambda存在以简化Boost和C ++ 11中的这个过程。


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

}

解决方案

erase() returns a new iterator:

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

Note that we can no longer compare it against a precalculated end, because we may erase it and therefore invalidate it. We must get the end explicitly each time.

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

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

Where pred is your removal predicate, such as:

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

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++11.

这篇关于从std :: vector中删除,同时为每个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆