12

イテレータでSTLコンテナを使用する一般的な誤用は何ですか?

4

9 に答える 9

21

コンテナー メンバーを挿入または削除してコンテナーを変更すると、反復子が無効になることがよくあることを忘れています。

STL の使用に関する多くの優れたヒントについては、Scott Meyers の本「Effective STL」を強くお勧めします (サニタイズされた Amazon リンク) 。

于 2009-02-03T12:26:29.153 に答える
9

ポインターの順序が保証されていないため、範囲の終了チェックでは < ではなく != を使用する必要があります。

例:

for(it = list.begin(); it != list.end(); ++it)
{
     // do stuff
}
于 2009-02-03T12:47:25.430 に答える
8

プリインクリメントで十分なポストインクリメント。

于 2009-02-03T12:36:47.930 に答える
7

他にもいくつか:

  • 反復子が指していた要素の 1 つ上の要素になることを忘れずに、逆反復子を基本反復子に変換します。

  • セットやマップなどの反復子でランダム アクセス反復子を必要とするアルゴリズムを使用しようとしています。

  • 非定数イテレータを使用してマップ エントリのキーを編集する (これはたまたま VS.Net でビルドされますが、GCC ではできません)

于 2009-02-03T13:52:32.130 に答える
6

Scott Meyers による「Effective STL」本を読まずにそれらを使用する。:) 本当。これにより、愚かなバグのほとんどがなくなります。

于 2009-02-03T13:17:02.483 に答える
6

の後に適切な継続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;
    }
}

これらの修正をいくつかの製品コードに適用しなければならなかったのは本当に何度もありました:(

于 2009-02-03T14:19:10.377 に答える
3

コンテナー内で auto_ptr を使用する。

list<auto_ptr<int> > foo;

幸いなことに、最近の auto_ptr 実装の多くは、これを不可能にするように書かれています。

于 2009-02-03T14:36:20.093 に答える
2

これは、STL コンテナーの問題だけではありません。ほとんどの場合、コンテナーを反復処理するときにコンテナーを変更すると、問題が発生します。

これは、ゲームのバグの非常に一般的な原因です。ほとんどのゲーム ループは、何かを実行している各ゲーム オブジェクトを反復処理することで構成されています。この何かがゲームオブジェクトコンテナから要素を追加または削除する場合、ほぼ確実にバグがあります。

解決策 - 2 つのコンテナー (objectsToDelete と objectsToAdd) を用意し、ゲーム コードでそのコンテナーにオブジェクトを追加し、ゲーム オブジェクト コンテナーを反復処理した後でのみ更新します。

objectsToAdd を設定して、何かを複数回削除しないようにすることができます。

オブジェクトをゲーム オブジェクト コンテナーに追加せずに構築できる場合は、objectsToDelete を Queue にすることができます。また、オブジェクト インスタンスが常に作成直後にゲーム オブジェクト コンテナーに追加されることをコードが想定している場合 (たとえば、コンストラクターで)、他のクラス (ObjectCreateCommand?) にすることもできます。 )。

于 2009-02-03T14:54:06.797 に答える
1
list<int> l1, l2;
// ...

for_each(l1.begin(), l2.end(), do_it());
于 2009-02-03T22:06:47.233 に答える