6

次のコードは期待どおりに動作します (テストはパスします) が、この方法で反復子を操作することは C++ では悪い習慣と見なされるのか、それとも問題ないのか疑問に思います。

おそらくこれは特定のものでstd::vectorあり、他のコレクションの動作は異なり、ベストプラクティスはコレクション (またはそれらの実装) 間で異なりますか?

他の言語では確かに問題があり、ほとんどの場合、コレクションを変更するとイテレータが無効になり、例外がスローされます。

BOOST_AUTO_TEST_CASE (ReverseIteratorExample) {
    std::vector<int> myvector;
    for(int i = 0; i < 5; i++)
    {
        myvector.push_back(i);
    }

    // is this generally a bad idea to change the vector while iterating?
    // is it okay in this specific case?
    myvector.reserve(myvector.size() + myvector.size() - 2 );
    myvector.insert(myvector.end(), myvector.rbegin() + 1, myvector.rend() -1);

    int resultset [8] = { 0,1,2,3,4,3,2,1 };
    std::vector<int> resultVector( resultset, resultset + sizeof(resultset)/sizeof(resultset[0]) );
    BOOST_CHECK_EQUAL_COLLECTIONS(myvector.begin(), myvector.end(), resultVector.begin(), resultVector.end());
}

まとめられた質問:

  1. これは、反復中にベクトルを変更するのは一般的に悪い考えですか?
  2. この特定のケースで大丈夫ですか?
  3. これは特定のコレクションでstd::vectorあり、他のコレクションの動作は異なりますか?
  4. ベスト プラクティスはコレクション (またはその実装) によって異なりますか?
4

1 に答える 1

12

これは有効なコードではありません。シーケンス コンテナーに対する操作の標準の定義 (23.2.3@4):

a.insert(p,i,j) - [...] pre: i と j は a への反復子ではありません。

したがって、コードは操作の前提条件に違反しているため、未定義の動作を呼び出しますinsert

を使用する代わりに、 toから反復してすべての値を呼び出すinsertループを記述した場合、コードは有効になります。これは、再割り当てが必要な場合にのみベクトル反復子を無効にするためであり、 を呼び出すと、これが当てはまらないことが保証されます。myvector.rbegin() + 1myvector.rend() -1push_backpush_backreserve

一般に、イテレート中にコンテナーを変更しても問題ない場合 (上記のループなど) はありますが、その際にイテレーターが無効化されないようにする必要があります。これがいつ発生するかは、各コンテナに固有です。

于 2013-04-23T16:18:06.340 に答える