0

ベクトルを反復処理するときにエラーを回避するための推奨される方法は何ですか。ベクトル内の任意の数の要素が(直接的または間接的に)要素の挿入または削除を引き起こす可能性があります-イテレータを無効にしますか?

具体的には、ベクトル内の要素がゲームオブジェクトである、ゲームプログラミングに関連して質問しています。他のオブジェクトを生成できるものもあれば、更新時に強制終了されて削除される必要があるものもあります。このため、追加されると予想される要素の数が完全に不明であるため、反復前に大容量を予約することもできません。

4

5 に答える 5

3

一概には言えません。イテレータが無効化される理由の 1 つは、無効化されたイテレータがどの要素を参照したいかを理解する方法がないためです。

たとえば、要素 3 の 5 への反復子があります。要素 2 を消去します。反復子は新しい要素 2 を指す必要があります (「同じ値が下に移動した」ため)、または新しい要素 3 を指す必要があります (なぜなら、それは「異なる値が下に移動したベクトルの同じ要素」です)?

実際には、次のオプションがあります。

  1. 他の誰かがイテレータを持っている間は、要素を挿入/消去しないでください。これは、別の機会に変更を加えるためにコードを変更することを意味します。
  2. イテレータの代わりにインデックスを使用します。これにより、上記の 2 番目のオプションが得られます (「インデックスは、新しい値を持つ同じ要素を参照します」)。インデックスが最後から外れるほど多くの要素を消去すると、インデックスも無効になる可能性があることに注意してください。
  3. 異なるイテレータ無効化規則で異なるデータ構造を使用します。たとえば、 astd::listは上記の最初のオプションを提供します(「イテレータは新しい位置の同じ要素を参照します」)

反復処理に使用している反復子は、その位置での単一要素の挿入/消去によって有害に無効化されてはなりません。これは無効になりますが、どちらの関数も反復処理を続行するために使用できる新しい反復子を返します。new iterator が参照する要素については、ドキュメントを参照してください。そのため、同じコンテナーで複数のイテレーターを使用している場合にのみ問題が発生します。

于 2012-12-10T13:30:43.277 に答える
1

ベクターは、集中的な挿入/削除をサポートするのに最適なコンテナーではない可能性があります (特にサイズが大きい場合)。ただし、ベクトルを使用する必要がある場合、最も安全な方法は、イテレータではなくインデックスを使用し、現在の位置の前に挿入/削除されているアイテムを追跡 (およびインデックスを調整) することです。このようにして、少なくとも再割り当ての問題を回避できます。

そして、反復ごとに v.size()/v.end() を再計算します。

于 2012-12-10T13:27:40.490 に答える
1

ここにいくつかのアイデアがあります:

  1. 整数インデックスを使用してベクトルを反復処理します。これは無効になりませんが、要素を挿入/削除するときに現在のインデックスを調整するように注意する必要があります。
  2. ベクトルのコピーを反復処理します。
  3. 進行中にベクトルを変更する代わりに、挿入/削除する必要があるものを追跡し、反復が終了した後に変更を適用します。
  4. リンクされたリストなど、別のコンテナーを使用します。
于 2012-12-10T13:28:17.843 に答える
0

もちろん、挿入と削除の際にイテレータを無効にしないコンテナを使用することで、問題を回避できます。

別のアプローチをお勧めしたいと思います。基本的に、ゲームの世界で新しい状態を作成するために、ベクトルを反復処理しています。ベクトルをトラバースするときに世界の状態を変更する代わりに、変更する必要があるものを新しいベクトルに格納します。次に、古い状態を完全に調べた後、新しいベクトルに保存した変更を適用します。

このアプローチには、1つの概念上の利点があります。すべてのオブジェクトの新しい状態は、古い状態のみに依存します。古い状態をトラバースするときに変更を適用し、1つのオブジェクトに関する決定が他のオブジェクトに依存する可能性がある場合、トラバースの順序が結果に影響を与える可能性があり、「早い」または「遅い」オブジェクトに不当な利点を与える可能性があります。

于 2012-12-10T13:51:36.150 に答える
0

別のベクターとstd::move、作成された新しい要素とともに削除されない要素を使用します。次に、古いベクトルをドロップします。

このようにして、元のベクトルから/へ何かを削除/挿入する必要はなく、イテレータは無効になりません。

于 2012-12-10T13:34:21.240 に答える