イテレータの特別な点は、アルゴリズムとコンテナの間の接着剤を提供することです。一般的なコードの場合、データ構造 ( 、、など)で念頭に置いている計算を実行する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
では機能しません。また、ループ制御は少し冗長です (init、check、increment)。C++ の 0 ベースのインデックス付けに注意する必要があります。list
forward_list
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) と同じに加えて、ループ制御 (チェックとインクリメントなし) のわずかな削減により、バグ率 (間違った初期化、チェックまたはインクリメント、off-by-one エラー) を大幅に削減できます。
欠点: 明示的なイテレータ ループと同じで、さらにループ内のフロー制御の可能性が制限され (continue、break、return を使用できません)、異なるストライドのオプションがありません (オーバーロードするイテレータ アダプタを使用しない限りoperator++
)。
4) range-for ループ
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
+ ラムダを使用します。