【问题标题】:STL list erase items [duplicate]STL列表擦除项目[重复]
【发布时间】:2011-04-21 11:11:22
【问题描述】:

可能重复:
Can you remove elements from a std::list while iterating through it?

我想在迭代时从列表中删除项目。我以前做过,但不知何故这个简单的例子让我失望了。 thnx 提前寻求帮助!

#include<iostream>
#include<list>
using namespace std;

void main()
{
    list<int> x;
    for ( int i =0;i<10; i++)
        x.push_back(i);

    for( list<int>::iterator k = x.begin(); k != x.end();k++)
        cout<<*k<<" ";

    cout<<endl;

    for( list<int>::iterator k = x.begin(); k != x.end();k++)
    {
        if ((*k)%2)
        {
            x.erase(k);
        }
    }

    cout<<endl;
    getchar();
}

【问题讨论】:

    标签: c++ stl


    【解决方案1】:

    当您这样做时,您的迭代器无效。做

    k = x.erase(k);
    

    【讨论】:

    • 这种情况下存在双倍递增的问题。以上解决了。
    • 你说得对,谢谢
    【解决方案2】:

    erase 返回被擦除元素之后的元素:http://www.cplusplus.com/reference/stl/vector/erase/

    所以试试这样的:

    for( list<int>::iterator k = x.begin(); k != x.end();)
      if( (*k)%2 )        
        k=x.erase(k);
      else
        ++k;
    

    【讨论】:

    • 2 个小点 a) k++ 优于 ++k(作为一种习惯)。特别是复杂类型(根据斯科特迈尔斯)。 b)我总是评论为什么我忽略了 for 的增量
    • @pm100 "k++ 优于 ++k(作为一种习惯)" - 我认为这确实是编码人员的偏好,除非您正在处理副作用问题。但就其本身而言,++k 或 k++ 都可以。我其实更喜欢第一种方式。
    • @dcp:特别是对于迭代器,它实际上可能具有性能影响,因为后缀版本实际上必须复制迭代器,并且一些迭代器足够“胖”,编译器无法在之后完全优化它内联。在这种特殊情况下,它是否会发生是非常值得怀疑的,但正如 pm100 所说,作为一种习惯,使用迭代器是一个好习惯。
    • @Pavel Minaev - 感谢您的解释。
    • @pm100: k++ 永远不会比 ++k 好,你可以期望的最好的就是编译器修复你的损坏代码,就像你写 ++k 一样(它这样做是因为人们不不必费心去理解每一个是什么意思)。此外,您说的是“增量 k”,而不是“k 增量”。
    【解决方案3】:

    FWIW,你所说的也可以用(例如)std::list::remove_if

    template <class T>
    class odd { 
        bool operator()(T const &value) { 
            return value % 2 != 0;
        }
    
    };
    
    // ...
    x.remove_if(odd);
    

    使用 C++ 0x 和/或 Boost lambda,您可以在不单独定义 even 的情况下执行此操作,这对于此类琐碎条件非常方便。从理论上讲,您也可以使用 std::bind1st、std::bind2nd、std::equal 和 std::modulus 的组合来定义它——但是(IMO)结果很难破译它会是不可取。

    请注意,std::list::remove_if(与 std::remove_if 不同)实际上会删除您要求删除的项目,而 std::remove_if 通常需要结合调用 erase 才能真正删除已删除的项目。

    【讨论】:

    • 老兄!不知道 Boost Lambda ..那真是太棒了。真的要更好地学习 STL 和 Boost……会让我的 C++ 日子变得如此轻松。那时我非常反对使用外部库……哈哈。这就是他们在学校教你如何编写收集类但忽略说“是的......但实际上不要在实践中编写这些”时发生的情况
    • @Mark:我不确定我会说从不编写你自己的集合类(有一些东西,比如默认情况下不包括环形缓冲区) ,但我说 1) 仅在必要时这样做,2) 确保它们是“集合”,因为 C++ 标准定义了这些术语,因此您可以将它们与标准算法、迭代器、等
    • 嗯..这就是我的意思。如果它们已经存在,请不要写它们;)不幸的是,实际上有很多情况需要专门的集合。
    • @Mark:是的——我同意这两点(尽管我不太确定是否有专门的收藏品有用途是不幸的)。
    • 用途并不可惜,可惜时不时得自己写:)
    【解决方案4】:

    无需编写另一个 for(;;) 循环来迭代 STL 容器,通常可以使用 STL 算法和 lambda 表达式更快地完成整个事情。

    您的示例代码可以重写为:

    list<int> x;
    
    int i = 0;
    generate_n(back_inserter(x), 10, [&i](){ return i++; });
    
    copy(x.begin(), x.end(), ostream_iterator<int>(cout, " "));
    cout << endl;
    
    x.remove_if([](int n){ return n%2==0; });
    

    【讨论】:

      猜你喜欢
      • 2014-12-21
      • 1970-01-01
      • 2017-07-18
      • 1970-01-01
      • 1970-01-01
      • 2020-06-14
      • 2011-09-29
      • 2017-09-22
      相关资源
      最近更新 更多