7

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

私はおそらく間違っていますが、とにかく助けていただければ幸いです。ありがとう。

4

4 に答える 4

24

ここでの中心的な問題はit、呼び出した後、イテレータ値で使用しeraseていることです。このeraseメソッドはイテレータを無効にするため、イテレータを使用し続けると動作が悪くなります。代わりに、のreturnを使用してerase、消去された値の次の有効なイテレータを取得します。

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

newList.end()また、に少なくとも5つの要素がない場合を説明するためのチェックを含めることも問題ありませんlist

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

ティムが指摘したように、ここにerase

于 2011-02-28T17:58:31.090 に答える
3

位置にある要素を消去するitと、イテレータitは無効になります。これは、解放したばかりのメモリを指します。

このerase(it)関数は、リストの次の要素を指す別のイテレータを返します。それを使って!

于 2011-02-28T18:00:01.260 に答える
2

erase()ループ内にいるときは、イテレータを無効にしています。消去ループの代わりに、次のようなことを行う方が簡単です。

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

また、 erase-removeイディオムにも興味があるかもしれません。

于 2011-02-28T18:00:48.790 に答える
2

私はこれをします:

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

どうやら読めない骨頭なので編集しました笑。

于 2012-04-28T15:50:39.103 に答える