当前位置:  开发笔记 > 编程语言 > 正文

你可以在迭代它时从std :: list中删除元素吗?

如何解决《你可以在迭代它时从std::list中删除元素吗?》经验,为你挑选了5个好方法。

我有代码看起来像这样:

for (std::list::iterator i=items.begin();i!=items.end();i++)
{
    bool isActive = (*i)->update();
    //if (!isActive) 
    //  items.remove(*i); 
    //else
       other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);

我想在更新后立即删除非活动项目,以避免再次走过列表.但是如果我添加注释掉的行,当我到达时会出现错误i++:"List iterator not incrementable".我尝试了一些替代品,它们没有在for语句中增加,但我无法得到任何工作.

当你走std :: list时,删除项目的最佳方法是什么?



1> Michael Kris..:

您必须首先递增迭代器(使用i ++),然后删除前一个元素(例如,使用i ++中返回的值).您可以将代码更改为while循环,如下所示:

std::list::iterator i = items.begin();
while (i != items.end())
{
    bool isActive = (*i)->update();
    if (!isActive)
    {
        items.erase(i++);  // alternatively, i = items.erase(i);
    }
    else
    {
        other_code_involving(*i);
        ++i;
    }
}


替代用法`i = items.erase(i)`更安全,因为它等同于列表,但是如果有人将容器更改为向量,它仍然可以工作.使用向量,erase()将所有内容移动到左侧以填充孔.如果你尝试删除最后一项,其代码在擦除后递增迭代器,则结束向左移动,迭代器向右移动 - **过去**结束.然后你崩溃了.
没有James,i在调用erase之前递增,并且先前的值被传递给函数.在调用函数之前,必须完全评估函数的参数.
@ James Curran:这不对.在调用函数之前,将完全评估所有参数.
马丁约克是对的.在调用函数之前,完全评估函数调用的所有参数,没有异常.这就是功能如何运作.它与你的foo.b(i ++)无关.c(i ++)例子(在任何情况下都是未定义的)
实际上,这不能保证工作.使用"erase(i ++);",我们只知道预递增的值传递给erase(),并且i在分号之前递增,不一定在调用erase()之前递增."iterator prev = i ++; erase(prev);" 肯定会工作,因为使用返回值
实际上,对于一个向量,你*希望*在每次迭代时重新计算`end`,因为它可能会移动.对于列表,它应该无关紧要.
我纠正了.请参阅Kristo的问题:http://stackoverflow.com/questions/598148/is-it-legal-to-use-the-increment-operator-in-ac-function-call/599564
使用`items.erase(i ++);`会在VS 2013中导致错误(它没有做应做的事情)。因此请使用`i = items.erase(i);`

2> MSN..:

你想做:

i= items.erase(i);

这将正确地更新迭代器以指向您删除的迭代器后的位置.


请注意,您不能将该代码放入for循环中.否则,每次删除元素时都会跳过一个元素.
迈克尔指出了一个巨大的"陷阱",我现在不得不处理同样的事情.我发现避免它的最简单方法就是将for()循环分解为while()并小心增量
他能不能我- 每次遵循他的一段代码来避免跳过?

3> Mike..:

您需要结合Kristo的答案和MSN:

// Note: Using the pre-increment operator is preferred for iterators because
//       there can be a performance gain.
//
// Note: As long as you are iterating from beginning to end, without inserting
//       along the way you can safely save end once; otherwise get it at the
//       top of each loop.

std::list< item * >::iterator iter = items.begin();
std::list< item * >::iterator end  = items.end();

while (iter != end)
{
    item * pItem = *iter;

    if (pItem->update() == true)
    {
        other_code_involving(pItem);
        ++iter;
    }
    else
    {
        // BTW, who is deleting pItem, a.k.a. (*iter)?
        iter = items.erase(iter);
    }
}

当然,效率最高的SuperCool®STLsavy就是这样的:

// This implementation of update executes other_code_involving(Item *) if
// this instance needs updating.
//
// This method returns true if this still needs future updates.
//
bool Item::update(void)
{
    if (m_needsUpdates == true)
    {
        m_needsUpdates = other_code_involving(this);
    }

    return (m_needsUpdates);
}

// This call does everything the previous loop did!!! (Including the fact
// that it isn't deleting the items that are erased!)
items.remove_if(std::not1(std::mem_fun(&Item::update)));



4> Mykola Golub..:

使用std :: remove_if算法.

编辑: 使用集合应该像:1.准备集合.2.流程收集.

如果你不混合这些步骤,生活会更容易.

    的std ::的remove_if.或list :: remove_if(如果你知道你使用list而不是TCollection)

    的std :: for_each的


std :: list有一个remove_if成员函数,它比remove_if算法更有效(并且不需要"remove-erase"成语).

5> David Cormac..:

这是一个使用for循环的示例,该循环在列表遍历期间被删除的情况下迭代列表并递增或重新验证迭代器。

for(auto i = items.begin(); i != items.end();)
{
    if(bool isActive = (*i)->update())
    {
        other_code_involving(*i);
        ++i;

    }
    else
    {
        i = items.erase(i);

    }

}

items.remove_if(CheckItemNotActive);

推荐阅读
农大军乐团_697
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有