6
vector<int> a;

1.

for(vector<int>::iterator it = a.begin(); it != a.end(); ++it)

2.

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)

どちらがより効率的ですか?または同じですか?

4

4 に答える 4

10

最初の批判:

1/典型的なチュートリアルの例

for(vector<int>::iterator it = a.begin(); it != a.end(); ++it)

魔法はありませんが、疑問が生じます:aエンド バウンドが変化する可能性があるループで変更されたことはありますか?

2/改善

vector<int>::iterator end = a.end();
for(vector<int>::iterator it = a.begin(); it != end; ++it)

a.end()一度だけ実行されるようです。ただし、endis notconstであるため、ループ内で変更される可能性があります。

endさらに、外側のスコープに識別子を導入し、それを汚染します。

したがって、パフォーマンスが向上する可能性はありますが、明確さはあまりありません。また、はるかに冗長です。


他にもいくつかの方法を提案します。

3/ベストマニュアル

for(vector<int>::iterator it = a.begin(), end = a.end(); it != end; ++it)

v1(非常に簡潔で、外部スコープの汚染がない)と(パフォーマンス)の利点を組み合わせていますが、ループ本体内で変更されたv2かどうかはまだ不明です。end

4/ブースト駆動

BOOST_FOREACH(int& i, a)

より簡潔v1で、一目ですぐに識別でき、外側のスコープ リークがなく、完全な反復が保証されます (境界を変更することはできません)。

不運にも:

  • 変数の型のカンマに問題があります (プリプロセッサに依存しているため)
  • コンパイル時のエラーは完全に不可解です (プリプロセッサに依存しているため)

注: 理論的には、std::foreachここでアルゴリズムを説明することもできますが、正直なところ、外部で述語を定義するには多大な労力が必要であり、コードの局所性が損なわれます。

5/ C++11 range-for ステートメント

for (int& i: a)

すべての利点:

  • 非常に簡潔
  • 最高の C++ 手書きループと同等のパフォーマンス
  • 完全な反復が保証され、質問はありません

また、問題はありません (スコープ リーク、プリプロセッサ マジック)。


BOOST_FOREACH個人的には、できる限り (趣味のプロジェクト)、それ以外の場合 (仕事中)に C++11 range-for を使用しています。

要素をフィルタリング/削除する必要がある場合は、STLアルゴリズムに依存することを好み、反復しているコンテナをペストのように変更することは避けます...境界条件とイテレータの無効化を台無しにするのは簡単です。

于 2012-04-27T07:49:06.393 に答える
6

2番目は、終了イテレータを1回作成するだけでよいため、より効率的です。

賢いコンパイラは最初のものを 2 番目に最適化するかもしれませんが、それが起こるとは保証できません。

コンパイラは、その後の end() の呼び出しが追加の効果を持たないか、別のものを返すことを 100% 確実にする必要があるため、実際には少し複雑な最適化になります。基本的に、少なくともループ全体で、end() は常に end() == end() への前の呼び出しのようなものを返すことを知る必要があります。コンパイラがその最適化を行うかどうかは保証されません。

于 2012-04-27T07:12:29.573 に答える
1

a.end()を 1 回だけ呼び出すため、2 番目の方法の方が明らかに優れています。本質的に、ツリーにN 個のノードがある場合、 a.end()へのN回の呼び出しを保存します。

于 2012-04-27T07:15:50.683 に答える
0

最初のforループの方が確実だと思います。このforループ内に要素を挿入/消去するendと、定義したイテレータは無効になります。例えば:

vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    // mbegin is automatically invalidated
    // execution of this program causes bizarre runtime_error !
    // never try this at home !
}

上記のコードのより安全なバージョンは次のようになります。

vector<int>::iterator mend = int_vec.end(), mbegin = int_vec.begin();
while(mbegin != mend)
{
    cout << *mbegin << " ";
    int_vec.erase(mbegin);
    mbegin = int_vec.begin(); // ok, mbegin updated.
}
于 2012-05-04T15:25:11.637 に答える