2016-06-11 8 views
2

std :: listの使い方に奇妙な動作が発生しました。問題は、リスト内の現在の要素を削除すると、その要素が無効になることです。 for(auto& iter : list)ループを持つ要素を調べると、削除されるはずだった要素に固執します。望ましくないstd :: listを削除した結果(C++)

#include <iostream> 
    #include <list> 
    #include <memory> 
    int main() { 
     std::list<unsigned int> wholeNumbers; 
     while(wholeNumbers.size() < 20) { 
      wholeNumbers.push_back(wholeNumbers.size()); 
     } 
     for(auto wholeNumber : wholeNumbers) { 
      std::cout << "Deleting entries. Value is: " << wholeNumber << std::endl; 
      std::cout << "Old size: " << wholeNumbers.size() << std::endl; 
      wholeNumbers.remove(wholeNumber); 
      std::cout << "New size: " << wholeNumbers.size() << std::endl; 
     } 
    } 

この所望の結果がインクリメント値吐き出すことであり、減分サイズ:私はこれを表示する最小のコンパイル例を有しています。しかし、私が経験している結果は次のとおりです。

Deleting entries. Value is: 0 
Old size: 20 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 1901208 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 0 
Old size: 19 
New size: 19 
Deleting entries. Value is: 1901208 
Old size: 19 
New size: 19 

これは無限に繰り返されます。

私のコンパイラの情報は次のとおりです。gcc version 5.3.0 (x86_64-posix-sjlj-rev0, Built by MinGW-W64 project)

私は私が意図したとおり、これは動作するはずと信じに間違えていた場合、私は好奇心が強いです。

敬具、

+0

イテレータを無効にしています。 – erip

+3

ああ。あなたのコメントを見て、それは最終的に手がかりになった。私はそれを無効にすると、ポインタはもはや要素に存在しなくなるので、無効になり、次のものに移動することができなくなる。したがって、要素を削除するには、 'for'ループの代わりに' remove_if'文で行う必要があります。ありがとうございました。 –

+0

スポットがあります。いい結論! – erip

答えて

2

:消去要素へ

参考とイテレータを無効にしています。

ループベースの範囲は暗黙のイテレータを使用します。 removeは、イテレータが指し示す要素を消去しているため、無効になり、未定義の動作が発生し、ハードドライブを消去する可能性があります。

代わりに、明示的なイテレータを取得します。 erase、ないremoveを呼び出し、反復継続するeraseの戻り値にイテレータを設定する(戻り値:「最後の削除の要素以下のIteratorを」)

+0

コメントの中で私が返信して言ったように、イテレータが無効になったと言われました。イレーズを続けるために 'erase'メソッドの頭をアップしてくれてありがとう! –

1

list::remove

イテレータの妥当性:機能によって取り除かれた要素を参照するイテレータ、ポインタや参照が無効化されます。

ループベースの範囲は、内部でイテレータを使用するため、イテレータを無効にすると期待される動作は期待できないものになります。

std::removeと違って、要素をコンテナの末尾に移動し、最初の「削除」へのポインタを返します。したがって、有名なerase-remove-idiom-list :: removeを必要とするのは実際にはデストラクタを呼び出します。 http://en.cppreference.com/w/cpp/container/list/eraseから

0

最初の反復では、あなたは成功したに沿って、最初の要素を削除しましたstd :: listの最初の要素と2番目の要素の間の接続を使用します。したがって、forループが、定義されていない値を持つ削除された要素を指すauto wholeNumberをstd :: listの2番目の要素に設定できないため、2番目の反復で問題が発生しました。

関連する問題