web-dev-qa-db-ja.com

リストイテレータRemove()

リストを調べてすべての偶数を削除するリストイテレータがあります。リストイテレータを使用して数値を正しく出力することはできますが、リストのremove()を使用して、逆参照されたイテレータを渡すことはできません。

Remove()ステートメントが有効な場合、* itrが破損することに気づきましたか?誰かがこれを説明できますか?

#include <iostream>
#include <list>

#define MAX 100

using namespace std;

int main()
{
    list<int> listA;
    list<int>::iterator itr;

    //create list of 0 to 100
    for(int i=0; i<=MAX; i++)
        listA.Push_back(i);

    //remove even numbers
    for(itr = listA.begin(); itr != listA.end(); ++itr)
    {
        if ( *itr % 2 == 0 )
        {
            cout << *itr << endl;
            listA.remove(*itr);    //comment this line out and it will print properly
        }
    }
}
14
Steve

上記のコードにはいくつかの問題があります。まず、removeは、削除された要素を指しているイテレータを無効にします。次に、イテレータの使用を続行します。 removeが複数の要素を削除する可能性があるため、一般的なケースでは(あなたの要素ではありませんが)どの要素が消去されるかを判断するのは困難です。

次に、おそらく間違った方法を使用しています。 Removeは、リスト内のすべてのアイテムを繰り返し処理して、一致する要素を探します。これは、1つしかないため、非効率的です。 eraseメソッドを使用する必要があるようです。おそらく、イテレータの位置にあるアイテムのみを消去する必要があります。 eraseの良いところは、次の有効な位置にあるイテレータを返すことです。それを使用する慣用的な方法は次のようなものです:

//remove even numbers
for(itr = listA.begin(); itr != listA.end();)
{
    if ( *itr % 2 == 0 )
    {
        cout << *itr << endl;
        itr=listA.erase(itr);
    }
    else
      ++itr;
}

最後に、remove_ifを使用して同じことを行うこともできます。

bool even(int i) { return i % 2 == 0; }

listA.remove_if(even);
44

参照している要素を削除した後は、イテレータを使用できません。

ただし、remove()の後に削除されていないアイテムを参照するリストイテレータは有効なままである必要があります。

2

次のようなものを使用できますか?

container.erase(it++);

私はこの例を試しました:

int main(){

 list<int>*a=new list<int>;
 a->Push_back(1);
 a->Push_back(2);
 a->Push_back(3);

 list<int>::iterator I;

 I=a->begin(); ++I;

 a->erase(I++);
 cout<<*I<<endl;
}

思い通りに3が表示されました。これが有効なのか、「機能する場合と機能しない場合がある」のかはわかりません。

編集:多分それはコンパイラのせいです。たとえば、私が使用しているコンパイラ(GNU gcc-g ++)は、リスト(std::)を循環として扱います。つまり、list-> end()の後にイテレータを増やすと、先頭に移動します。

0
rimad