在迭代std :: list时进行擦除 [英] Erasing while iterating an std::list

查看:88
本文介绍了在迭代std :: list时进行擦除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我在for循环中使用iterator,并且在当前迭代器的迭代器上使用erase,则for循环应该可以继续正常工作并访问其余的list元素?

根据我的阅读,应该是这种情况,并且是listdequevector的主要区别.就我的目的而言,queue可能有效,但是我需要这种行为.

这是我正在考虑的循环:

    std::list<Sequence>::iterator iterator;
    iterator=m_concurrents.begin();
    for (;iterator!=m_concurrents.end();++iterator){
        if (iterator->passes()){
            m_concurrents.erase(iterator);
        }
    }

解决方案

编写该循环的惯用方式是:

for (auto i = list.begin(); i != list.end();) {
    if (condition)
        i = list.erase(i);
    else
        ++i;
}

您可以对setmultisetmapmultimap执行相同的操作.对于这些容器,您可以删除一个元素,而不会影响其他元素的任何迭代器的有效性.其他容器,例如vectordeque都不是很好.对于那些容器,只有擦除的迭代器之前的元素保持不变.这种差异仅是因为list将元素存储在单独分配的节点中.删除一个链接很容易. vector是连续的,取出一个元素会将所有元素移回一个位置.

由于在某些给定条件下擦除了i处的元素,因此循环中断了.在该调用之后,i不再是有效的迭代器.然后,您的for循环递增i,但是i无效.地狱随之而来.这就是确切的情况,这就是为什么erase在删除了内容之后将迭代器返回到元素的原因...,因此您可以继续遍历list.

您还可以使用 list::remove_if :

list.remove_if([](auto& i) { return i > 10; });

在lambda中,如果应删除该元素,则返回true.在此示例中,它将删除所有大于10的元素.

If I'm using an iterator in a for loop and I use erase on a current iteration of iterator, the for loop should continue fine and access the rest of the list elements?

From what I have read, this should be the case and is a primary distinguishing characteristic of list vs deque or vector. For my purposes, a queue might work but I need this behavior.

Here is the loop I am considering:

    std::list<Sequence>::iterator iterator;
    iterator=m_concurrents.begin();
    for (;iterator!=m_concurrents.end();++iterator){
        if (iterator->passes()){
            m_concurrents.erase(iterator);
        }
    }

解决方案

The idiomatic way to write that loop would be:

for (auto i = list.begin(); i != list.end();) {
    if (condition)
        i = list.erase(i);
    else
        ++i;
}

You can do the same thing with a set, multiset, map, or multimap. For these containers you can erase an element without affecting the validity to any iterators to other elements. Other containers like vector or deque are not so kind. For those containers only elements before the erased iterator remain untouched. This difference is simply because lists store elements in individually allocated nodes. It's easy to take one link out. vectors are contiguous, taking one element out moves all elements after it back one position.

Your loop is broken because you erase the element at i on some given condition. i is no longer a valid iterator after that call. Your for loop then increments i, but i is not valid. Hell upon earth ensues. This is the exact situation that is why erase returns the iterator to the element after what was erased... so you can continue traversing the list.

You could also use list::remove_if:

list.remove_if([](auto& i) { return i > 10; });

In the lambda, return true if the element should be removed. In this example, it would remove all elements greater than 10.

这篇关于在迭代std :: list时进行擦除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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