5

膨大な数のデータを含む arr というベクトルがあり、そのベクトル内のすべての値を出力するとします。私はどちらかを使用します:

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}

私の意見では、実装の最初の方法はベクトルのサイズをキャッシュにフェッチするため、最初のミスの後で状態が速くなります。2回目の実装はどうですか?遅いですか?システムは、条件を満たすたびに size() メソッドを呼び出しますか?

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

4

5 に答える 5

6

任意の本体を持つループを一般化すると、指定した 2 つのバリアントの間に 1 つの重要な違いがありarrます。ループ中に のサイズが変化した場合はどうなりますか?

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

しかし、ループ本体が外部関数を呼び出すほどである場合 (可能性が高い)、この仮定を行うことができなくなり、arr.size()すべてのループ反復をチェックする必要があります。

そうは言っても、arr.size()おそらくローカル変数に値を格納するよりも遅くない単純な構造体メンバーアクセスにうまくいくでしょう。がポインタarrまたは参照である場合を除き、それは間接的であり、次にアクセスであるため、最初のバージョンは少し高速になります。

それが特に一般的な実行ループであり、何らかの理由で最適化せずにコンパイルする必要がある場合は、最初のケースを使用して高速化することをお勧めします。

しかしその 1 行余分にコードの可読性が損なわれることはほとんどありませんね。

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

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

于 2012-04-30T10:20:22.307 に答える
4

可能であれば、インデックスの代わりにイテレータを使用することをお勧めします。例えば:

C++ の場合:

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

C# の場合:

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

c++ の利点の 1 つは、ベクトルの代わりにリストがある場合です。ベクトルでは size() は O(1) ですが、リストでは O(n) です。また、これにより、arr.Size() が何度も呼び出される状況が回避されます。

一般的な利点は、c# と c++ の両方でより読みやすいコードですが、それでも使用できない状況がいくつかあり、インデックスを使用する必要があります。

于 2012-04-30T10:25:57.060 に答える
1

十分に最新のコンパイラがある場合:

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

または、さらに良いことに...独自のfor-loop をローリングしないでください (これは、C++11 より前のコンパイラでも機能します)。

std::copy(arr.begin(), arr.end(), std::ostream_iterator<int>(std::cout, ","));
于 2012-04-30T10:35:56.493 に答える
0

2 番目のオプションの方が優れています。

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

変数 i は、ループが終了した後に解放されます。arr.size() は、ループが初期化されると計算されます。arr_size 変数を格納するためのメモリは割り当てられません。

于 2012-04-30T10:13:10.963 に答える