【问题标题】:How do I remove element pointed to by iterator in a C++ list?如何删除 C++ 列表中迭代器指向的元素?
【发布时间】:2020-06-30 04:26:58
【问题描述】:

如何删除 C++ 列表中迭代器指向的元素?为什么这不起作用?

int main()
{
    list<int> l;
    l.push_back(5);
    l.push_back(6);

    
    for(auto &it: l)
    {
        l.erase(*it);
    }

    return 0;
}

【问题讨论】:

  • 在迭代项目时从std::vector 中删除项目是不好的。查阅std::vector::erase的文档和示例代码,了解如何安全使用。
  • 还有clear 方法可以从列表中删除所有元素。
  • 为什么这不起作用:1)在for(auto &amp;it: l) 中,是int,而不是迭代器,所以erase 不会接受它。 B) 如果你确实有一个迭代器,eraseing it in list 让你有一个迭代器指向一个不再在列表中的项目。您不能使用它来查找list 中的下一项。

标签: c++ c++11 erase stdlist


【解决方案1】:

为什么

for(auto &it: l){
    l.erase(*it);
}

无法工作:

it 不是迭代器。在range-based for loop 中,在冒号之前声明的变量range_declaration 将接收容器中的一个项目,在这种情况下为int。由于it 将收到intauto 将推断出int 的类型,从而导致

for(int &it: l){
    l.erase(*it);
}

std::list::erase 需要一个迭代器。我假设* 只是一些鸟枪调试的结果,看看取消引用被认为是迭代器的东西是否有帮助(它不会)。

旁注:在使用基于范围的 for 循环迭代容器时,您无法从容器中删除项目。实现 for 循环的后台魔法看起来像

{
    auto cur = container.begin() ;
    auto end = container.end();
    for ( ; cur != end; ++cur) 
    {
        auto val = *cur;
        do_stuff 
    }
}

如果您在do_stuff 中从容器中删除cur,则++cur 无效。由于cur 不再在容器中,因此您不能使用它前进到容器中的下一个项目。 std::list 在其iterator invalidation rules 中非常宽容。当缓存的end 迭代器失效时,许多容器会失败。

如何解决:

给定的代码似乎试图清空list 中的所有项目。 std::list::clear 只需一个函数调用即可为您做到这一点。

如果你想释放特定元素或按值选择元素,你应该使用std::list::remove or std::list::remove_ifstd::list::erase一起使用

例如:

l.erase(l.remove(5), l.end()); // remove all elements containing the number 5

如果您想删除第一项,std::list::pop_front。要删除最后一项,std::list::pop_back。如果您想按位置删除任何其他元素,则必须有该位置的有效迭代器(如果您还没有,请参阅std::advance),然后调用erase。请注意,如果您必须进行大量迭代才能找到要删除的项目,std::list 可能不适合这项工作,因为 list 迭代很昂贵,并且很快就会消除廉价插入和删除的好处。

【讨论】:

    【解决方案2】:
    int main()
    {
        list<int> l;
        list<int>::iterator it;
        l.push_back(5);
        l.push_back(6);
        l.push_back(7);
        it=l.begin();// points to the first element
        l.erase(it);//pass the iterator to the erase method
        
        for(auto i=l.begin();i!=l.end();i++){
            cout<<*i<<" ";
        }
    
        return 0;
    }
    

    假设你想删除第一个元素。然后简单地将列表的迭代器传递给擦除方法。

    【讨论】:

      【解决方案3】:

      如果你想在循环中执行 cpprefenrence 有很好的例子

      当使用erase方法移除一个元素时,它返回下一个iterator到被移除的元素,如果最后一个元素end将返回;

      std::list<int> l{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
      

      从上面的列表中,假设您要删除 4 和 5;

      下面是方法;

      std::list<int>::iterator first = l.begin();
      
      std::advance( first, 4 );
      auto it = l.erase( first ); // removes 4 and returns iterator to element 5
      l.erase( it ) // removes 5;
      

      按照其他人的建议:

      for(auto &it: l){ // range based loop, iterating through elements ex: 4, 5, 6
        //l.erase(*it);
        std::cout << it; // prints 4, 5, 6
      
      }
      

      您需要低于for loop 来增加iterator

      for( auto it = l.begin(); it != l.end(); it++) 
      {
         // do something hear
      }
      

      【讨论】:

        【解决方案4】:

        如果使用基于迭代器的循环,可以使用erase的返回值来更新迭代器:

          std::list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        
          for (auto it = l.begin();
               it != l.end();
               ++it)
          {
            if (*it % 3 == 0)
            {
              it = l.erase(it);
            }
          }
          for (auto i : l)
          {
            std::cout << i << std::endl;
          }
        

        【讨论】:

          猜你喜欢
          • 2018-07-02
          • 2016-07-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-07-18
          • 2013-11-25
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多