简体   繁体   English

在std :: list上使用擦除时的C ++分段

[英]C++ Segmentation when using erase on std::list

I'm trying to remove items from a C++ linked list using erase and a list iterator: 我正在尝试使用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;
}

I get this output and can't seem to trace the reason: 我得到此输出,似乎无法跟踪原因:

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

I'm probably doing it wrong, but would appreciate help anyway. 我可能做错了,但是无论如何,我们将不胜感激。 thanks. 谢谢。

The core problem here is you're using at iterator value, it , after you've called erase on it. 这里的核心问题是,你正在使用的迭代器值, it ,你叫后erase就可以了。 The erase method invalidates the iterator and hence continuing to use it results in bad behavior. erase方法会使迭代器无效,因此继续使用它会导致不良行为。 Instead you want to use the return of erase to get the next valid iterator after the erased value. 相反,您想使用erase的返回值来获取擦除值之后的下一个有效迭代器。

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

It also doesn't hurt to include a check for newList.end() to account for the case where there aren't at least 5 elements in the list . 包括检查newList.end()来解决list中至少包含5个元素的情况也没有什么坏处。

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

As Tim pointed out, here's a great reference for erase 正如Tim所指出的,这是erase的绝佳参考

When you erase an element at position it , the iterator it gets invalidated - it points to a piece of memory that you just freed. 当您在位置删除元素it ,迭代器it变得无效-它指向一块内存,你刚刚释放。

The erase(it) function returns another iterator pointing to the next element to the list. erase(it)函数返回另一个迭代器,该迭代器指向列表的下一个元素。 Use that one! 用那个!

I do this: 我这样做:

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

Edited because I'm a bonehead that can't read apparently lol. 已编辑,因为我是一个看不懂大声笑的笨蛋。

You're invalidating your iterator when you erase() within the loop. 当您在循环中erase()时,您使迭代器无效。 It would be simpler to do something like this in place of your erase loop: 做这样的事情来代替擦除循环会更简单:

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

You might also be interested in the erase-remove idiom . 您可能也对“ 擦除删除”这一惯用语感兴趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM