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)
どちらがより効率的ですか?または同じですか?
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)
どちらがより効率的ですか?または同じですか?
最初の批判:
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()
一度だけ実行されるようです。ただし、end
is 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)
すべての利点:
また、問題はありません (スコープ リーク、プリプロセッサ マジック)。
BOOST_FOREACH
個人的には、できる限り (趣味のプロジェクト)、それ以外の場合 (仕事中)に C++11 range-for を使用しています。
要素をフィルタリング/削除する必要がある場合は、STLアルゴリズムに依存することを好み、反復しているコンテナをペストのように変更することは避けます...境界条件とイテレータの無効化を台無しにするのは簡単です。
2番目は、終了イテレータを1回作成するだけでよいため、より効率的です。
賢いコンパイラは最初のものを 2 番目に最適化するかもしれませんが、それが起こるとは保証できません。
コンパイラは、その後の end() の呼び出しが追加の効果を持たないか、別のものを返すことを 100% 確実にする必要があるため、実際には少し複雑な最適化になります。基本的に、少なくともループ全体で、end() は常に end() == end() への前の呼び出しのようなものを返すことを知る必要があります。コンパイラがその最適化を行うかどうかは保証されません。
a.end()を 1 回だけ呼び出すため、2 番目の方法の方が明らかに優れています。本質的に、ツリーにN 個のノードがある場合、 a.end()へのN回の呼び出しを保存します。
最初の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.
}