1. ホーム
  2. c++

[解決済み] イテレータループとインデックスループの比較【重複あり

2022-03-03 10:35:41

質問

<ブロッククオート

重複の可能性があります。
なぜ配列のインデックスではなくイテレータを使用するのですか?

C++の知識を復習しているところ、イテレータに行き当たりました。私が知りたいことの一つは、それらを特別なものにして、私はなぜこれが知りたいです。

using namespace std;

vector<int> myIntVector;
vector<int>::iterator myIntVectorIterator;

// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);

for(myIntVectorIterator = myIntVector.begin(); 
        myIntVectorIterator != myIntVector.end();
        myIntVectorIterator++)
{
    cout<<*myIntVectorIterator<<" ";
    //Should output 1 4 8
}

はこれよりマシです。

using namespace std;

vector<int> myIntVector;
// Add some elements to myIntVector
myIntVector.push_back(1);
myIntVector.push_back(4);
myIntVector.push_back(8);

for(int y=0; y<myIntVector.size(); y++)
{
    cout<<myIntVector[y]<<" ";
    //Should output 1 4 8
}

そして、std 名前空間を使うべきでないことも知っています。この例はcprogrammingのウェブサイトから持ってきただけです。では、なぜ後者の方が悪いのか、教えていただけませんか?何が大きく違うのでしょうか?

どのように解決するのですか?

イテレータの特別な点は、イテレータが アルゴリズムとコンテナ . 一般的なコードでは、STLアルゴリズムを組み合わせて使うことをお勧めします。 find , sort , remove , copy ) などのデータ構造に対して、思い描いた計算を実行する ( vector , list , map など) を作成し、そのアルゴリズムとイテレータをコンテナに供給します。

あなたの特別な例では、このような組み合わせで書くことができます。 for_each アルゴリズムと vector コンテナ (以下のオプション 3) を参照) を使用することもできますが、これは std::vector を反復処理する4つの異なる方法のうちの1つでしかないのです。

1) インデックスに基づく反復処理

for (std::size_t i = 0; i != v.size(); ++i) {
    // access element as v[i]

    // any code including continue, break, return
}

メリット : C スタイルのコードに慣れた人なら誰でも知っている、異なるストライドを使ってループさせることができる (例. i += 2 ).

デメリット シーケンシャル・ランダム・アクセス・コンテナ ( vector , array , deque の場合、動作しません。 list , forward_list または連想コンテナです。また、ループの制御は少し冗長です(init, check, increment)。C++の0ベースインデックスを意識する必要がある。

2) イテレータを用いた反復処理

for (auto it = v.begin(); it != v.end(); ++it) {
    // if the current index is needed:
    auto i = std::distance(v.begin(), it); 

    // access element as *it

    // any code including continue, break, return
}

メリット : より汎用的で、すべてのコンテナ (新しい順不同の連想コンテナも含む) で動作します。また、異なるストライド (たとえば std::advance(it, 2) );

デメリット 現在の要素のインデックスを取得するために余分な作業が必要になる (list や forward_list では O(N) になる可能性がある).ループ制御がやや冗長(init, check, increment)。

3) STL for_each アルゴリズム + ラムダ

std::for_each(v.begin(), v.end(), [](T const& elem) {
     // if the current index is needed:
     auto i = &elem - &v[0];

     // cannot continue, break or return out of the loop
});

メリット 2)と同様、ループ制御の削減(チェック&インクリメントなし)、バグ率の低減(初期化、チェック&インクリメント、オフバイワンエラー)、など。

デメリット 明示的なイテレータループと同じですが、ループ内のフロー制御の可能性が制限されます (continue, break, return が使用できません)。 operator++ ).

4) 範囲指定ループ

for (auto& elem: v) {
     // if the current index is needed:
     auto i = &elem - &v[0];

    // any code including continue, break, return
}

メリット 非常にコンパクトなループ制御、現在の要素への直接アクセス。

デメリット インデックスを取得するための余分なステートメントがある。異なるストライドを使用することができない。

何を使うか?

を反復処理する特定の例では std::vector もし本当にインデックスが必要なら(例えば前の要素や次の要素にアクセスしたり、ループ内でインデックスを表示したりログに残したり)、あるいは1以外のストライドが必要なら、明示的なインデックスループを、それ以外なら range-for ループを使うでしょう。

一般的なコンテナ上の一般的なアルゴリズムの場合、ループ内のフロー制御がなく、ストライド1が必要なコードでなければ、明示的なイテレータ・ループを使いますが、その場合はSTL for_each + ラムダ