在为每个执行一次时从 std::vector 中擦除?

Posted

技术标签:

【中文标题】在为每个执行一次时从 std::vector 中擦除?【英文标题】:Erasing from a std::vector while doing a for each? 【发布时间】:2010-10-15 01:30:03 【问题描述】:

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

基本上我想做的是:

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】:

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_iferase() 结合起来。你从 O(N2) (每个元素都会被擦除和移动)变为 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());

注意 lambda 的存在是为了简化这个过程,无论是在 Boost 还是 C++11 中。

【讨论】:

我不确定我是否理解第一种方法是N平方的,为什么不是N,我只迭代一次以删除项目。 当然,除非擦除返回的迭代器将您带回顶部 @Milo:这是 N^2。如果您删除第一个元素,所有其他元素将被复制下来以取而代之。这样做 N 次,你已经触摸了每一个 N^2 次。您可以将参数传递给谓词,谓词会转发它。 第一个 sn-p 可能是错误的,因为 end 迭代器在擦除后会失效。 我不会在每次循环迭代时重新评估 end(),就在调用 erase() 时:for(iterator it = vec.begin(), end = vec.end(); it != end;) ... if (condition) it = vec.erase(it); end = vec.end(); ...

以上是关于在为每个执行一次时从 std::vector 中擦除?的主要内容,如果未能解决你的问题,请参考以下文章

在为 Flutter 编写测试时,当相似的方面出现不止一次时会发生啥?如何筛选出合适的?

具有来自多个类的值的 C++ std::vector

AWS.ApiGatewayManagementApi.postToConnection() 调用一次时执行两次

在某个阈值后,Std::vector 填充时间从 0ms 变为 16ms?

查找 std::vector 中每个唯一值的频率的有效方法

将 std::vector<int> 的每个值重置为 0 的最快方法