首页 文章

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

提问于
浏览
214

我有代码看起来像这样:

for (std::list<item*>::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" . 我尝试了一些没有任何工作的替代品 .

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

11 回答

  • -4

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

    std::list<item*>::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;
        }
    }
    
  • 4

    你想做:

    i= items.erase(i);
    

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

  • 2

    您需要结合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 != items.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

    使用std :: remove_if算法 .

    Edit: 与馆藏合作应如下:1 . 准备馆藏 . 2.流程收集 .

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

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

    • std :: for_each

  • 253

    Kristo答案的循环版本的替代方案 .

    你会失去一些效率,你会向后退,然后在删除时再转发,但为了换取额外的迭代器增量,你可以在循环范围内声明迭代器,代码看起来更清晰一些 . 选择什么取决于当下的优先事项 .

    答案完全没有时间,我知道......

    typedef std::list<item*>::iterator item_iterator;
    
    for(item_iterator i = items.begin(); i != items.end(); ++i)
    {
        bool isActive = (*i)->update();
    
        if (!isActive)
        {
            items.erase(i--); 
        }
        else
        {
            other_code_involving(*i);
        }
    }
    
  • 2

    下面是一个使用 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);
    
  • 10

    删除仅使指向已删除元素的迭代器无效 .

    因此,在这种情况下,删除* i后,i无效,您无法对其进行增量 .

    你可以做的是首先保存要删除的元素的迭代器,然后递增迭代器,然后删除保存的迭代器 .

  • 2

    你可以写

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

    您可以使用 std::list::remove_if 编写等效代码,该代码更简洁,更明确

    items.remove_if([] (item*i) {
        bool isActive = (*i)->update();
        if (!isActive) 
            return true;
    
        other_code_involving(*i);
        return false;
    });
    

    当items是向量而不是列表时,应该使用 std::vector::erase std::remove_if 成语以保持O(n)处的复杂性 - 或者如果您编写通用代码并且项目可能是一个没有有效方法来擦除单个项目的容器(如向量) )

    items.erase(std::remove_if(begin(items), end(items), [] (item*i) {
        bool isActive = (*i)->update();
        if (!isActive) 
            return true;
    
        other_code_involving(*i);
        return false;
    }));
    
  • 111

    如果您将 std::list 视为一个队列,那么您可以将所有要保留的项目出列并排队,但只能将要删除的项目出列(而不是入队) . 这是一个例子,我想从包含数字1-10的列表中删除5 ...

    std::list<int> myList;
    
    int size = myList.size(); // The size needs to be saved to iterate through the whole thing
    
    for (int i = 0; i < size; ++i)
    {
        int val = myList.back()
        myList.pop_back() // dequeue
        if (val != 5)
        {
             myList.push_front(val) // enqueue if not 5
        }
    }
    

    myList 现在只有1-4和6-10的数字 .

  • 0

    我总结了一下,这里有三个方法,例如:

    1.使用while循环

    list<int> lst{4, 1, 2, 3, 5};
    
    auto it = lst.begin();
    while (it != lst.end()){
        if((*it % 2) == 1){
            it = lst.erase(it);// erase and go to next
        } else{
            ++it;  // go to next
        }
    }
    
    for(auto it:lst)cout<<it<<" ";
    cout<<endl;  //4 2
    

    2.在列表中使用remove_if成员功能:

    list<int> lst{4, 1, 2, 3, 5};
    
    lst.remove_if([](int a){return a % 2 == 1;});
    
    for(auto it:lst)cout<<it<<" ";
    cout<<endl;  //4 2
    

    3.使用std :: remove_if功能结合擦除成员函数:

    list<int> lst{4, 1, 2, 3, 5};
    
    lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){
        return a % 2 == 1;
    }), lst.end());
    
    for(auto it:lst)cout<<it<<" ";
    cout<<endl;  //4 2
    

    4.使用for循环,应注意更新迭代器:

    list<int> lst{4, 1, 2, 3, 5};
    
    for(auto it = lst.begin(); it != lst.end();++it){
        if ((*it % 2) == 1){
            it = lst.erase(it);  erase and go to next(erase will return the next iterator)
            --it;  // as it will be add again in for, so we go back one step
        }
    }
    
    for(auto it:lst)cout<<it<<" ";
    cout<<endl;  //4 2
    
  • 20

    我觉得你有一个bug,我这样编码:

    for (std::list<CAudioChannel *>::iterator itAudioChannel = audioChannels.begin();
                 itAudioChannel != audioChannels.end(); )
    {
        CAudioChannel *audioChannel = *itAudioChannel;
        std::list<CAudioChannel *>::iterator itCurrentAudioChannel = itAudioChannel;
        itAudioChannel++;
    
        if (audioChannel->destroyMe)
        {
            audioChannels.erase(itCurrentAudioChannel);
            delete audioChannel;
            continue;
        }
        audioChannel->Mix(outBuffer, numSamples);
    }
    

相关问题