2017-01-20 3 views
2

ヨハネス・シャウブはhereイテレータにプレフィックスインクリメントフォームを使用する理由

は常にその定義があなたが知らない イテレータのための前置インクリメント形式を使用しますと主張しています。これにより、コードの実行には が可能です。

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) { 
    /* std::cout << *it; ... */ 
} 

なぜこの最初の反復は、その後、(v.begin()は、+ 1で)ループを開始しませんか?あなたのコードが

for(std::vector<T>::iterator it = v.begin(); it != v.end();) { 
    /* std::cout << *it; ... */ 
    ++it; 
} 

、あなたが++itを書く場合、それは問題ではないことは容易に理解できるであろうと同じです

答えて

2

なぜこれを最初に反復しないのですか?ループを開始します(v.begin()+ 1)。

繰り返しステートメントは、常に各繰り返しの最後に実行されます。これは、使用するインクリメント演算子のタイプに関係なく、またはインクリメント演算子をまったく使用するかどうかに関係なくです。

繰り返しステートメントの式の結果は使用されないため、ループの動作には影響しません。声明:

++it; 

は、文と機能的に同等です:

it++; 

のPostfixと前置インクリメント式は、式の結果が使用されている場合にのみ、異なる動作を持っています。


なぜイテレータのための前置インクリメント形式を使用できますか?

ポストフィックス操作はコピーを意味するためです。イテレータをコピーするのは一般的には少なくとも遅くてもイテレータをコピーしない場合よりも遅くなる可能性があります。

後置インクリメントの典型的なインプリメンテーション:結果を使用しない場合

iterator tmp(*this); // copy 
++(*this);   // prefix increment 
return tmp;   // return copy of the temporary 
        // (this copy can be elided by NRVO) 

、さらに最初のコピーを離れて最適化することができるが、操作がインライン展開されている場合にのみ。しかし、それは保証されていません。


私は盲目的に "常にプレフィックスインクリメントをイテレータで使用する"というルールを使用しません。いくつかのアルゴリズムはポストフィックスで表現する方が明確ですが、それは私の意見です。後置インクリメントするのに適したアルゴリズムの例:

template<class InIter, class OutIter> 
OutIter copy(InIter first, InIter last, OutIter out) { 
    while(first != last) 
     *out++ = *first++; 
    return out; 
} 
2

注意。またはit++;。それは式があると評価するものであるとして(これはまた、あなたの最終点に対処しています。)

しかし概念的it++は、その実装では、unincremented値のコピーを保存する必要があります。

itは、価値の高いコピーを取得するのに計算コストがかかり、コンパイラがit++で取得した暗黙的な値のコピーを最適化できない場合があります。

式の値が使用されていない場合は、これらの日は、最もコンテナのため、コンパイラは++itit++間違いなく明確に最適化します。すなわち、生成されたコードは同一である。

私は可能な限り事前にインクリメントを使用常に著者のアドバイスやに従いますが、私は昔ながらの(I)古いものと、それは主にダウン個人の選択にですので、専門のプログラマーの多くは、ないこと(ⅱ)承知しています。

1

なぜこの最初の反復が、その後ループを開始しない(v.beginで()+ 1)?

for loopはとして解析されますので:だから

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) { 
    /* std::cout << *it; ... */ 
} 

はそれが最初でv.begin()でループを行うだろうことを意味し

{ 
    std::vector<T>::iterator it = v.begin(); 
    while (it != v.end()) { 
    /* std::cout << *it; ... */ 
    ++it ; 
    } 
} 

と同等です

{ 
    init_statement 
    while (condition) { 
    statement 
    iteration_expression ; 
    } 
} 

、次に進むit。接頭辞インクリメントとは、値を大きくしてから、増加したオブジェクトの参照を返します。返されたオブジェクトがこのケースではまったく使用されていないことがわかりますが、++itit++は同じ結果につながります。

関連する問題