イテレータでSTLコンテナを使用する一般的な誤用は何ですか?
9 に答える
コンテナー メンバーを挿入または削除してコンテナーを変更すると、反復子が無効になることがよくあることを忘れています。
STL の使用に関する多くの優れたヒントについては、Scott Meyers の本「Effective STL」を強くお勧めします (サニタイズされた Amazon リンク) 。
ポインターの順序が保証されていないため、範囲の終了チェックでは < ではなく != を使用する必要があります。
例:
for(it = list.begin(); it != list.end(); ++it)
{
// do stuff
}
プリインクリメントで十分なポストインクリメント。
他にもいくつか:
反復子が指していた要素の 1 つ上の要素になることを忘れずに、逆反復子を基本反復子に変換します。
セットやマップなどの反復子でランダム アクセス反復子を必要とするアルゴリズムを使用しようとしています。
非定数イテレータを使用してマップ エントリのキーを編集する (これはたまたま VS.Net でビルドされますが、GCC ではできません)
Scott Meyers による「Effective STL」本を読まずにそれらを使用する。:) 本当。これにより、愚かなバグのほとんどがなくなります。
の後に適切な継続erase()
。
仮定:
Container::iterator i = cont.begin(), iEnd = cont.end();
たとえば、std::map
では、これは良い考えではありません。
for (; i != iEnd; ++i) {
if (i->second.eraseCondition()) {
cont.erase(i);
}
}
これはうまくいきます:
for (; i != iEnd; ) {
Container::iterator temp = i;
++temp;
if (i->second.eraseCondition()) {
cont.erase(i);
}
i = temp;
}
そしてこれも:
for (; i != iEnd; ) {
if (i->second.eraseCondition()) {
cont.erase(i++);
}
else {
++i;
}
}
これらの修正をいくつかの製品コードに適用しなければならなかったのは本当に何度もありました:(
コンテナー内で auto_ptr を使用する。
list<auto_ptr<int> > foo;
幸いなことに、最近の auto_ptr 実装の多くは、これを不可能にするように書かれています。
これは、STL コンテナーの問題だけではありません。ほとんどの場合、コンテナーを反復処理するときにコンテナーを変更すると、問題が発生します。
これは、ゲームのバグの非常に一般的な原因です。ほとんどのゲーム ループは、何かを実行している各ゲーム オブジェクトを反復処理することで構成されています。この何かがゲームオブジェクトコンテナから要素を追加または削除する場合、ほぼ確実にバグがあります。
解決策 - 2 つのコンテナー (objectsToDelete と objectsToAdd) を用意し、ゲーム コードでそのコンテナーにオブジェクトを追加し、ゲーム オブジェクト コンテナーを反復処理した後でのみ更新します。
objectsToAdd を設定して、何かを複数回削除しないようにすることができます。
オブジェクトをゲーム オブジェクト コンテナーに追加せずに構築できる場合は、objectsToDelete を Queue にすることができます。また、オブジェクト インスタンスが常に作成直後にゲーム オブジェクト コンテナーに追加されることをコードが想定している場合 (たとえば、コンストラクターで)、他のクラス (ObjectCreateCommand?) にすることもできます。 )。
list<int> l1, l2;
// ...
for_each(l1.begin(), l2.end(), do_it());