イテレータを使用してベクトルのインデックスを取得する
質問
ベクトルの要素を反復処理する場合は、インデックスの代わりに反復子を使用することをお勧めします (「 なぜ配列インデックスの代わりに反復子を使用するのでしょうか?).
std::vector<T> vec;
std::vector<T>::iterator it;
for ( it = vec.begin(); it != vec.end(); ++it )
{
// do work
}
ただし、ループの本体でインデックスを使用することが必要になる場合があります。この場合、パフォーマンスと柔軟性/拡張性を考慮すると、次のどれが望ましいでしょうか?
- インデックス付きループに戻る
std::vector vec; size_t i; for ( i = 0; i < vec.size(); ++i ) { // use i }
- オフセットの計算
std::vector vec; std::vector::iterator it; for ( it = vec.begin(); it != vec.end(); ++it ) { size_t i = it - vec.begin(); // use i }
- std:: distance を使用する
std::vector vec; std::vector::iterator it; for ( it = vec.begin(); it != vec.end(); ++it ) { size_t i = std::distance( vec.begin(), it ); // use i }
解決
ベクトルのみを使用することを計画している場合は、反復子ループよりも意図をより明確に伝えるため、インデックス付きループに戻すことをお勧めします。ただし、将来のプログラムの進化によりコンテナーが変更される可能性がある場合は、イテレーターにこだわり、すべての標準イテレーターで動作することが保証されている std:: distance を使用する必要があります。
他のヒント
std:: distance の使用は、ランダム アクセス反復子だけでなくすべての反復子に対して機能するため、もう少し汎用的です。また、ランダム アクセス イテレータの場合、It - vec.begin() と同じくらい高速である必要があります。
それ - vec.begin() は基本的にポインター算術です。
std::distance(vec.begin(), it)
インデックスを提供します it
を指していると仮定して、 vec
.
カール
インデックス付きループに戻ります。
基本的に 90% の場合、反復子の方が優れていますが、これはそのうちの 10% の 1 つです。イテレータを使用するそもそもの理由はコードを単純化することだったのに、イテレータを使用するとコードがより複雑になり、理解しにくくなります。
解決策が 1 つ欠けています。必要な場合に備えてインデックスを保持しますが、ループ条件としては使用しないでください。リストでも動作し、コスト (ループあたり) は O(n) と追加のレジスターです。
私は、将来の開発上の理由から、常にイテレータを使用する傾向があります。
上記の例では、おそらく std::vector を std::set に交換することにした場合 (要素の一意のコレクションが必要な可能性があります)、反復子と distance() の使用は引き続き機能します。
パフォーマンスの問題は無視できるレベルまで最適化されると確信しています。
ベクトルの場合、私は常に整数メソッドを使用します。ベクトルへの各インデックスは、配列の検索と同じ速度です。値を頻繁に使用する場合は、便宜上、その値への参照を作成します。
ベクトル反復子は、ポインター演算を使用してリストを反復処理するため、理論的にはインデックスよりもわずかに高速になる可能性があります。ただし、通常は、可読性は実行時の最小限の違いに見合うだけの価値があると思います。
私は他のコンテナタイプにイテレータを使用します。また、ループ変数が必要ない場合もあります。しかし、ループ変数が必要な場合は、ループの入力を難しくするだけです。(c++0x の auto が待ちきれません。)