ループ内で変数を定義するのは良いですか?[閉まっている]


15

私のインストラクターはかつて、ループ内で変数を定義するべきではないと教えてくれましたが、正直なところまだ理由がわかりません。

その欠点は何ですか?

体はそれを私に説明できますか?


7
インストラクターはどのプログラミング言語を教えていましたか?
ブライアン

2
ループ内で非プリミティブ型を使用して変数を定義すると、プログラムはループのたびにコンストラクターを不必要に呼び出すことになります。ループ外で一度だけ定義する必要がある場合は、それを行います。
ブランディン

17
インストラクターが言っていることについてこのような混乱がある場合、最良のリソースはインストラクターに尋ねることです。Q&Aサイトでは提供できない密なやり取りを提供できます。

1
クロスサイト複製:ループの前またはループ内の変数の宣言の違い?(そしてもちろん、そのような基本的な質問(C ++のみに関する質問を含む)については、そのサイトに多くの重複があります)。
ピーターモーテンセン

2
そのアドバイスはコンテキストに固有のものでした。個人的なスタイルの問題として、const(関数型プログラミングの習慣)をしない理由がない限り、変数を宣言することを好みます。私はそれらを変更せず、オプティマイザはそれらが必要でないときを検出する必要があります。そうでなければ、私は深刻なバグを防ぎます。これらの定数中間値がループの反復に固有である場合、それはループ内でそれらを宣言することを意味します。ただし、ループ外で変数を宣言する必要があるもう1つのタイミングは、ループ外で変数を参照するときです。たとえば、保存している結果。
デイビスラー

回答:


42

ループ内で変数を定義することは問題ではありません。実際、識別子は可能な限り最小のスコープに限定する必要があるため、それは良い習慣です。

ループが実行される前に一度だけ変数を割り当てることができれば、ループ内で変数を割り当てることは悪いことです。割り当ての右側がどれだけ複雑かによっては、これはかなり高価になり、ループの実行時間を支配することさえあります。すべての反復で同じ計算値を使用するループを作成する場合は、ループの上で確実に計算する必要があります。これは、スコープを最小化するよりも重要です。

明確にするために:compute()常に同じ値を返す限り、これは

int value = compute();
while (something) {
    doSomething(value);
}

これよりも賢い:

while (something) {
    int value = compute();
    doSomething(value);
}

2
ループ内で変数をどのように定義し、ループの前に変数を割り当てますか?
仮面の男

6
@MaskedMan、あなたは誤解していると思う。Kilianが意味したのは、ループの各反復中に同じ値が割り当てられた変数がある場合、たとえば同じ日付変数がに設定されている1/1/1900場合、変数は宣言され、値はループの前に割り当てられます。
ps2goat

2
過去20年間に(学部生のコンパイラコース以外で)記述されたコンパイラが、各反復で同じ値を割り当てていることを把握できず、その割り当てをループ外に移動したとは思わない。
TMN

14
@tmn:明快にコードを明快にして、自分でできることをコンパイラにさせないでください。
ロバートハーベイ

10
@TMN、必ずしもではありません。その最適化は、コンパイラーが計算に副作用がないことを証明できる場合にのみ可能です。
ポールドレーパー

16

複合型には、重要なコンストラクタとデストラクタがあります。

これらは、ループ本体の開始時と終了時に呼び出されます(初期化されて範囲外になるため)。初期化がメモリの割り当てが必要なほど高価な場合は、回避する必要があります。

ただし、些細なタイプの場合は問題ありません。割り当てと割り当て解除自体は、スタックポインタから値を加算および減算するだけです。(最適化されます)


ありがとう、まさに私が探していた答えです!
-gebbissimo

6

まあ、彼のアドバイスは少し単純すぎます(控えめな表現です)。
それはすべての方法の範囲に続いて良いアイデアを超える人々の心配悪い考え不可能

  1. 再利用のほうが古いものを破壊して新しいものを作成するよりも安い場合は、必ずそれに従う必要があります。

    #include <iostream>
    #include <string>
    
    int main() {
        std::string s; // Don't needlessly free the buffer
        while ((std::cin >> s))
            std::cout << s;
    }
  2. パフォーマンスにとって重要でない場合は、スタイルの問題としてそれを避ける必要があります。

    #include <stdio.h>
    #include <stdlib.h>
    int f(int, int);
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            int x = rand(); // Declared here so you don't need to hunt it down.
            printf("%d => %d\n", x, f(x-1, x+i));
        }
    }
  3. あなたは本当にそれが悪化し、性能や間違った意味を持っているときにそれを避ける必要があります。

    #include <iostream>
    #include <string>
    std::string generate(int);
    
    int main() {
        for(int i = 0; i < 100; ++i) {
            std::string s = generate(i); // Using copy-ellision here
            std::cout << s;
        }
    }
  4. 使用されているタイプがスワッピング、移動割り当て、コピー割り当てのいずれも許可していない場合は、それに従うことはできません

    #include <iostream>
    #include <puzzle>
    
    int main() {
        for (int i = 0; i < 100; ++i) {
            Puzzle x(i); // Puzzle is an immutable class. For whatever reasons.
            std::cout << x;
        }
    }

2
「ループ内」の定義に応じて、1をfor (std::string s; std::cin >> s;) ...「外部」に変更しても、「外部」のままにすることができます
-Caleth
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.