首页 >后端开发 >C++ >如何在使用基于范围的 For 循环迭代期间安全地删除 std::vector 中的元素?

如何在使用基于范围的 For 循环迭代期间安全地删除 std::vector 中的元素?

Susan Sarandon
Susan Sarandon原创
2024-11-03 17:09:03927浏览

How to Safely Erase Elements from a std::vector During Iteration with a Range-Based For Loop?

使用基于范围的 For 循环迭代时从 std::vector 中删除元素

迭代 std::vector 并删除匹配特定条件的元素可能是编程中的常见任务。然而,标准的基于范围的 for 循环语法提出了挑战,因为在迭代时尝试擦除元素可能会使迭代器无效。

在基于范围的 For 循环内擦除的问题

以下代码片段演示了该问题:

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

}

虽然目的是删除满足条件的元素,但这种方法是不正确的。当一个元素被删除时,迭代器就变得无效。继续使用该迭代器进行迭代会导致未定义的行为。

解决方案 1:使用常规 For 循环和显式迭代器操作

一种解决方案是使用常规 for 循环使用显式迭代器操作:

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

请注意这里的关键区别:我们在每次迭代上显式调用 end(container) 以获得新的结束迭代器。这是必要的,因为擦除元素会使原始迭代器失效。

解决方案 2:使用 std::remove_if 和擦除

更有效的替代方案是组合 std:: remove_if和erase():

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

std::remove_if删除与指定谓词匹配的元素,而erase()删除它们。此方法将第一个解决方案中的时间复杂度从 O(N2) 降低到 O(N)。

特定于所提供示例的解决方案

在给出的具体示例中,以下代码可用于删除与特定小部件关联的定时事件:

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

    template <typename T> // for now a template
    bool operator()(const T&amp; 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());

以上是如何在使用基于范围的 For 循环迭代期间安全地删除 std::vector 中的元素?的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn