5

なぜ次のように印刷されるの2ですか?

list<int> l;
l.push_back( 1 );
l.push_back( 2 );
l.push_back( 3 );
list<int>::iterator i = l.begin();
i++;
l.erase( i );
cout << *i;

eraseが返ってくるかはわかりますが、なぜこれでいいのでしょうか。それとも未定義ですか、それともコンパイラに依存しますか?

4

5 に答える 5

15

はい、それは未定義の動作です。一種のワイルドポインタを間接参照しています。iafterの値は使用しないでくださいerase

そして、はい、ポイントされたオブジェクトをerase 破壊します。ただし、PODタイプの場合、破棄は何もしません。

erase消去されるイテレータに特別な「null」値を割り当てないため、イテレータは無効になります。

于 2011-03-11T14:20:28.980 に答える
2

オブジェクトを「破棄する」とは、そのメモリが再利用され、その内容が変更される可能性があることを意味します (主に手書きのデストラクタがそうする場合、およびおそらく空きメモリ関連のものを所定の場所に格納した結果として)。list::erase は、引数として渡されたものの代わりに使用する必要がある新しいイテレータを返します (i = l.erase(i);ハビットを作成したくなるでしょう)。

破壊は決して、記憶が一掃され、一掃されることを意味するものではありません。以前に有効だった場所は、ほとんどの場合、CPU の観点からはまだ有効ですが(つまり、値をフェッチできます)、他の操作がいつでも目的に応じてその場所をリサイクルする可能性があるため、信頼することはできません。

*iセグメンテーション違反が発生する可能性はほとんどありませんが、ポインターを使用するより複雑な型では発生する可能性がありますが、新しい値が含まれている可能性があります。

他のコレクションには、リストよりも事前に確認できる動作がある場合があります。IIrc、ベクトルはストレージ領域を圧縮するため、以前の値はi、まれにさらに逆参照することによってのみ表示されます。

于 2011-03-11T14:28:34.467 に答える
1

リンクリストを扱っているので、リストの要素はメモリ内で互いに「背後」にある必要はありません。ベクトルで同じことを試してみると、(動作が定義されていないため)経験する可能性があります

cout << *i

2として印刷されます。

ただし、これはプログラミングの非常に安全な方法ではありません。したがって、イテレータを消去したら、begin()やend()などで再度初期化しない限り、イテレータを再度使用しないようにしてください。

于 2011-03-11T14:33:29.580 に答える
1

適切なオプションと適切なコンパイラを使用してコードをコンパイルし、実行してみてください。(VC++ では/D_DEBUG /EHs /MDd十分なようです。-D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC少なくとも g++ では、両方のコンパイラに一般的にさらに多くのオプションが必要です。) クラッシュするはずです。(私が試したときはそうでした。)

于 2011-03-11T18:04:14.810 に答える
1

イテレータはまだこのメモリを指しているようです....
このブロックに何かを書き込むと、
次回* iはセグメンテーション違反をスローするでしょう..

憶測ですがすみません

于 2011-03-11T14:23:54.553 に答える