ベクトルの最後の要素を指すときにイテレータを2ずつインクリメントするとどうなりますか? この質問 では、2つの要素によってSTLコンテナーにイテレーターを調整する方法を尋ねる2つの異なるアプローチが提供されます。
イテレータがSTLコンテナの最後の要素またはそれ以降を指している場合、EdgeケースについてVC++ 7でそれらの両方をテストしました。
vector<int> vec;
vec.Push_back( 1 );
vec.Push_back( 2 );
vector<int>::iterator it = vec.begin();
advance( it, 2 );
bool isAtEnd = it == vec.end(); // true
it++; // or advance( it, 1 ); - doesn't matter
isAtEnd = it == vec.end(); //false
it = vec.begin();
advance( it, 3 );
isAtEnd = it == vec.end(); // false
私はベクトルと他のコンテナを横断するときにvector :: end()と比較することを勧める場合があります:
for( vector<int>::iterator it = vec.begin(); it != vec.end(); it++ ) {
//manipulate the element through the iterator here
}
明らかに、イテレータがループ内の最後の要素を超えて進んだ場合、for-loopステートメントの比較はfalseと評価され、ループは未定義の動作に喜んで継続します。
反復子でadvance()または任意の種類のインクリメント操作を使用し、コンテナの終わりを超えてポイントすると、この状況を検出できないことを正しく理解できますか?もしそうなら、ベストプラクティスは何ですか-そのような進歩を使用しないでください?
以下はニコライ・ジョスティスの本からの引用です:
Advance()はシーケンスのend()を超えるかどうかをチェックしないことに注意してください(イテレータは一般に、それが動作するコンテナを知らないためチェックできません)。したがって、この関数を呼び出すと、シーケンスの終わりに対する演算子++の呼び出しが定義されていないため、未定義の動作になる可能性があります。
つまり、イテレーターを範囲内に維持する責任は呼び出し元にあります。
おそらく次のようなものが必要です:
template <typename Itr>
Itr safe_advance(Itr i, Itr end, size_t delta)
{
while(i != end && delta--)
i++;
return i;
}
iterator_category<Itr>
はrandom_access_iterator
次のようなことを行います。
return (delta > end - i)? end : i + delta;
イテレータ(it)とvec.begin()のイテレータの間で「距離」関数を使用し、それをベクトルのサイズ(size()で取得)と比較できます。
その場合、forループは次のようになります。
for (vector<int>::iterator it = vec.begin(); distance(vec.begin(), it) < vec.size(); ++it)
{
// Possibly advance n times here.
}
Marijnが示唆するコードは、わずかに間違っています(curiousguyが指摘したように)。
最終行の正しいバージョンは次のとおりです。
bool isPastEnd = it >= vec.end();
Boost.Range をご覧になることをお勧めします。
使用する方が安全かもしれません。
C++ 0xにも含まれます。
Forステートメントでさらに比較を行うこともできます。
for( vector<int>::iterator it = vec.begin(); it != vec.end() && it+1 != vec.end(); it+=2 ) {
//manipulate the element through the iterator here
}
これがどのように実行されるかはわかりません Kostas's 提案ですが、それはfeels少しずつ増加する方が良いようです。もちろん、それぞれをチェックする必要があるため、大きな増分ではかなり維持できませんが、別のオプションです。
可能な場合は、絶対に避けます。一度に2つの値をインクリメントする必要がある場合は、std :: pairのベクトルまたは2つの要素を持つ構造体のベクトルを持つことを検討してください。
container.end()
-終了直後の要素-は唯一定義されている外部値です。
チェックされたイテレータは、本質的に範囲外のアクセスに障害を起こしますが、それはそれほど役に立ちません(特にデフォルトの動作はプログラムを終了することです)。
私はベストプラクティスは「それをしないで」だと思います-イテレータのすべての値をチェックし(フィルタとしてラップされたものが望ましい)、興味深いエントリのみを操作するか、明示的にインデックスを使用します
for(int i = 0; i < vec.size(); i+=2) {...}