2012-04-30 5 views
4

膨大な数のデータを含むarrというベクトルがある場合、そのベクトルのすべての値を出力します。私が使用し、次のいずれかC++:arr.size()はループに適していますか?

int arr_size = arr.size(); 
for(int i=0; i<arr_size; ++i) {//print the values} 

またはそれをこのように実装します。私の意見では

for(int i=0; i<arr.size(); ++i) {//print the values} 

を、第1の実施の方法は、キャッシュへのベクターのサイズを取得し、それ故により速く状態を行います最初のミスの後。 2番目の実装はどうですか?それは遅いですか?条件を満たすたびにsize()メソッドが呼び出されますか?

編集:C++を使用しているとしましょう。

+1

あなたが使用している言語は、このことが重要かどうかに影響を与える可能性があります。 – Mat

+0

@Mat、コンパイラはどうですか? – nullpotent

+0

@AljoshaBre:コンパイラ(とコンパイラオプション)は言語よりも重要です(明らかに悪いコンパイラや非常に洗練されたデバッグオプションがこれに影響します) – Mat

答えて

6

一般化された体のループの一般化、あなたが与えた2つの変種の間には1つの重要な違いがあります:ループの間にarrのサイズが変わるとどうなりますか?

コンパイラが変更しないと仮定できる場合は、arr.size()が呼び出されるようにループを最適化することができ、生成されるコードは最初のケースとほぼ同じになります。

しかし、ループ本体が外部関数を呼び出している(可能性が高い)場合、この仮定はもうできません。ループの繰り返しごとにarr.size()をチェックする必要があります。

arr.size()は、おそらく、ローカル変数に値を格納するよりも遅くならない単純な構造体メンバアクセスになるので、最初のバリアントを使用して得られることはあまりありません。 arrがポインタまたは参照である場合は間接的なものであり、その後のアクセスでない限り、最初のバージョンはlitteとなります。

特に一般的に実行されるループで、何らかの理由で最適化せずにコンパイルする必要がある場合は、高速化するために最初のケースに進んでください。

しかし、のコードの読みやすさは、その余分な行によってまったく損なわれていませんか?

要約すると、ループがタイトでなければならない内部ループでない限り、私はバリアント2に行きます。その場合は、私はバリアント1を確実に使用します。

もちろん、要素がループ内のarrに追加され、ループがそれらの要素をカバーする必要がある場合は、2番目の変種のみが正しくなります。

+0

また、 'arr'が関数に渡された場合、コンパイラーは別のスレッドがそれを変更しているかどうかを知ることができないため、.size()が変更されないことは危険です。 –

+2

@MatthewWatson別のスレッドが物事を変更していて、ロックやその他の同期がない場合は、未定義の動作です。したがって、コンパイラはこれが当てはまらないと仮定することができます。 –

0

2番目のオプションは、より良いです:

for(int i=0; i<arr.size(); ++i) {//print the values} 

ループが終わった後、私がリリースされる変数。 ループが初期化されると、arr.size()が計算されます。 メモリはarr_size変数の格納に割り当てられません。

+1

または、もしc#タグが何かを意味するなら、あなたはforeachを使うことができます。 –

+0

私にはC++のように見えます。彼はそれを "ベクトル"と呼び、 "size()"は小文字とそのメソッドで始まり、プロパティではありません。変数名にはアンダースコアが含まれています。 ;) –

+0

パフォーマンスに関する質問は、同じ構文の両方の言語にも当てはまります。 –

4

インデックスの代わりにイテレータを使用することが可能な場合は、私はお勧めします。 e。G:Cの++で

:C#で

for(const_iterator it = arr.begin(), ite = arr.end(); 
    it != ite; ++it) 
{ 
.... 
} 

:あなたの代わりにベクトルのリストを持っているときのC++で

foreach(var item in arr){....} 

利点の一つは、(ベクトルの大きさで)O(1であります)しかし、リストではそれはO(n)です。また、これは、arr.Size()を何度も呼び出す状況を防ぎます。

一般的な利点は、C#とC++の両方で読み易いコードですが、それでも使用できない状況があり、インデックスを使用する必要があります。あなたは現代の十分なコンパイラがある場合

+0

これは、実際にはイテレーターを使用して良い方法です!提案していただきありがとうございます。 – xiaoyao

+0

このヘルプが必要です。 –

+0

2つの無関係な宣言をそうするのは合法ですか? 'for(const_iterator it = arr.begin()、ite = arr.end(); ...)'ではありませんか? – jamesdlin

1

:より良いまだ

for (auto i: arr) 
{ 
    //print the values 
} 

かを...あなた自身のfor -loopを転がり避ける(これも、事前にC++ 11件のコンパイラで動作します):

std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ","));