3

コードがこのように動作する理由を理解するのに苦労しています。まず第一に、関連する回答資料を読みましたが、それでも説明が少し進んでいることがわかりました。誰かがこれを簡単な方法で説明できるかどうか疑問に思っています。

わかりましたので、リストから要素を消去しています。

リストには、奇数と偶数の両方の int 要素が含まれています。この部分はわかります。リストから奇数を削除するために最初に書いたコードは次のとおりです

for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
    {
        if(*i%2 == 0 )
        {
             lNo.erase(i);
        }
        else
        {
             cout << " " << *i;
        }
     }

このコードでは、プログラムは単にコンパイルされず、プログラムをシャットダウンする必要があるというメッセージを読みました。

このコードを書くと、消去関数が機能します。

for(list<int>::iterator i = lNo.begin(); i != lNo.end(); i++)
    {
        if(*i%2 == 0 )
        {
             i = lNo.erase(i);  
        }
        else
        {
            cout << " " << *i;
        }
   }

lNo.erase(i)だけではなく、i = lNo.erase(i)をコーディングするとプログラムが機能する理由を理解する必要がありますか?

シンプルで簡潔な回答をいただければ幸いです。コンテナーごとに異なる制約があることはわかっているので、元のコードで違反したのはどの制約ですか?

4

3 に答える 3

6

ドキュメントに記載されているように、erase関数は渡された反復子を無効にします。つまり、再度使用することはできません。ループはその反復子では続行できません。

ドキュメントには、消去された要素の後の要素にイテレータを返すことも記載されています。その反復子は有効であり、続行するために使用できます。

ただし、消去された要素の次の要素にイテレータを返すため、それをインクリメントして進める必要がないことに注意してください。そうしないと、その要素の奇数がチェックされません。ループはそれを処理し、消去が行われなかった場合にのみインクリメントする必要があります。

于 2013-01-14T13:27:11.010 に答える
5

Even your second code is incorrect.

The correct code should be this:

for(list<int>::iterator i = lNo.begin(); i != lNo.end(); /*NOTHING HERE*/ )
{
    if(*i%2 == 0 )
    {
         i = lNo.erase(i);  
    }
    else
    {
        cout << " " << *i;
        ++i; //INCREMENT HERE, not in the for loop
    }
}

erase()アイテムを消去し、イテレータを次のアイテムに戻すことに注意してください。つまり、i消去するときにコードをインクリメントする必要はありません。i代わりに、からの戻り値で更新する必要がありますerase

次のように使用できますerase-remove idiom

lNo.erase(std::remove_if(lNo.begin(),
                         lNo.end(),
                         [](int i) { return i%2 == 0; }), 
                         lNo.end());

ライブデモ

于 2013-01-14T13:26:12.207 に答える
0

問題は、リストの連鎖が変更されることを期待していないイテレータを使用していることです。したがって、リストで erase() を呼び出すと、チェーンが効果的に変更されるため、イテレータは無効になります。i++ ステートメントは機能しなくなりました。

ただし、2 番目のバージョンでは、イテレータをチェーンをそのまま保持している有効なオブジェクトに再割り当てするため、i++ ステートメントは引き続き機能します。

一部のフレームワークでは、2 種類のイテレータがあります。1 つは基になるデータセットに何が起こっているかをすぐに反映するタイプ (ここで使用しているものです)、もう 1 つは基になるデータセットに何が起こっても連鎖を変更しない種類です (そのため、2 番目のバージョンの奇妙なトリックを使用する必要はありません)。

于 2013-01-14T13:32:17.660 に答える