使用基于范围的 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& 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中文网其他相关文章!