【问题标题】:C++ Segmentation when using erase on std::list在 std::list 上使用擦除时的 C++ 分段
【发布时间】:2011-07-05 23:05:41
【问题描述】:

我正在尝试使用 erase 和列表迭代器从 C++ 链表中删除项目:

#include <iostream>
#include <string>
#include <list>

class Item
{
  public:
    Item() {}
    ~Item() {}
};

typedef std::list<Item> list_item_t;


int main(int argc, const char *argv[])
{

  // create a list and add items
  list_item_t newlist;
  for ( int i = 0 ; i < 10 ; ++i )
  {
    Item temp;
    newlist.push_back(temp);
    std::cout << "added item #" << i << std::endl;
  }

  // delete some items
  int count = 0;
  list_item_t::iterator it;

  for ( it = newlist.begin(); count < 5 ; ++it )
  {
    std::cout << "round #" << count << std::endl;
    newlist.erase( it );
    ++count;
  }
  return 0;
}

我得到了这个输出,但似乎无法追踪原因:

added item #0
added item #1
added item #2
added item #3
added item #4
added item #5
added item #6
added item #7
added item #8
added item #9
round #0
round #1
Segmentation fault

我可能做错了,但无论如何都希望得到帮助。谢谢。

【问题讨论】:

    标签: c++ linked-list segmentation-fault erase


    【解决方案1】:

    这里的核心问题是,在您调用 erase 之后,您使用的是迭代器值 iterase 方法使迭代器无效,因此继续使用它会导致不良行为。相反,您想使用erase 的返回值来获取擦除值之后的下一个有效迭代器。

    it = newList.begin();
    for (int i = 0; i < 5; i++) {
      it = newList.erase(it);
    }
    

    检查newList.end() 以解决list 中至少没有5 个元素的情况也没有什么坏处。

    it = newList.begin();
    for (int i = 0; i < 5 && it != newList.end(); i++) {
      it = newList.erase(it);
    }
    

    正如Tim 所指出的,这是erase 的一个很好的参考

    【讨论】:

    • 比我的答案更好。你不想将它结合起来++和擦除,这巧妙地回避了这一点。但我确实喜欢分享一些我最喜欢的参考页面的链接:list::erase
    • @Tim,添加了对我答案的引用。对于 C++ STL 问题,这也是我的转到页面。
    【解决方案2】:

    我这样做:

    for(list<type>::iterator i = list.begin(); i != list.end(); i++)
    {
         if(shouldErase)
         { 
            i = list.erase(i);
            i--;
         }
    }
    

    编辑是因为我是个看不懂的傻瓜,哈哈。

    【讨论】:

    • 接受的答案没有跳过问题:循环不会增加迭代器 it,而是一个整数计数器 i
    • 哦,是的,我想念他们的不同,哈哈。愚蠢的t。编辑我的答案
    • 虽然我也看不出答案中的代码是如何工作的。除非我又是个白痴,否则代码似乎会尝试删除列表的开头,然后是下一个项目,下一个项目,直到我到达 5。
    • 因为问题是关于删除列表的前 5 项。但无论如何,从循环语句中删除 i++ 并将其作为 else 子句会更好。
    • 是的,我认为这样会更好。问题是关于修复 seg 错误,而不仅仅是删除列表的前五个元素。这恰好是他想要做的事情。
    【解决方案3】:

    当您在循环中erase() 时,您正在使迭代器无效。做这样的事情来代替你的擦除循环会更简单:

    list_item_t::iterator endIter = newlist.begin();
    std::advance(endIter, 5);
    newList.erase(newlist.begin(), endIter);
    

    您可能还对erase-remove idiom 感兴趣。

    【讨论】:

      【解决方案4】:

      当您擦除位置 it 的元素时,迭代器 it 将失效 - 它指向您刚刚释放的一块内存。

      erase(it) 函数返回另一个迭代器,指向列表的下一个元素。使用那个!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-22
        • 2011-07-13
        • 2013-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多