5

次のいずれかを実行した場合(この質問の目的では同等であると想定しています)

for(int i=0; i<A; i++)
{
  //... do stuff
  for(int j=0; j<B; j++)
  {
    //... do stuff
  }
  //... do stuff
}

for(int i=0; i<A; i++)
{
  int j;
  //... do stuff
}

変数jはループごとにスタック上で再作成されますか (ループSPごとに常に更新されます)、または関数が一度にいくつのローカル変数を持つ可能性があるかを知るのに十分なほど賢いコンパイラーは、関数の入り口でスタック?

これは理論的にはコンパイラに依存することは理解していますが、このような単純なことはすべての主要なコンパイラに共通していると思います。そうでない場合、誰かがコンパイラについて具体的GCCに知っていますか?VC++

4

4 に答える 4

9

効率的です。gcc最近のほとんどのコンパイラと同様に、それを最適化します。また、Donald Knuth 氏の次の言葉も覚えておいてください。

約 97% の確率で、わずかな効率性を忘れる必要があります。時期尚早の最適化は諸悪の根源です。

アセンブリコードを比較することで効率的であることを確認できます。たとえばdiff、比較を行うために使用します。アセンブリ使用-Sフラグを生成するには、gcc -S. デフォルトの最適化レベルは 0 であるため、これは と同等gcc -S -O0です。したがって、最低レベルの最適化でも、gccがこの変数を処理します。

最初のバージョン (読みやすくするために、この方法をお勧めします):

#include <stdio.h>

int main()
{
    for (int i = 0; i < 10; i++)
    {
        for (int j = 0; j < 10; j++)
        {
            printf("%d ", i + j);
        }
    }
    return 0;
}

2 番目のバージョン:

#include <stdio.h>

int main()
{
    for (int i = 0; i < 10; i++)
    {
        int j;
        for (j = 0; j < 10; j++)
        {
            printf("%d ", i + j);
        }
    }
    return 0;
}

同一のアセンブリ結果:

    .file   "main.cpp"
    .section    .rodata
.LC0:
    .string "%d "
    .text
.globl main
    .type   main, @function
main:
.LFB0:
    .cfi_startproc
    .cfi_personality 0x3,__gxx_personality_v0
    pushq   %rbp
    .cfi_def_cfa_offset 16
    movq    %rsp, %rbp
    .cfi_offset 6, -16
    .cfi_def_cfa_register 6
    subq    $16, %rsp
    movl    $0, -4(%rbp)
    jmp .L2
.L5:
    movl    $0, -8(%rbp)
    jmp .L3
.L4:
    movl    -8(%rbp), %eax
    movl    -4(%rbp), %edx
    leal    (%rdx,%rax), %eax
    movl    %eax, %esi
    movl    $.LC0, %edi
    movl    $0, %eax
    call    printf
    addl    $1, -8(%rbp)
.L3:
    cmpl    $9, -8(%rbp)
    setle   %al
    testb   %al, %al
    jne .L4
    addl    $1, -4(%rbp)
.L2:
    cmpl    $9, -4(%rbp)
    setle   %al
    testb   %al, %al
    jne .L5
    movl    $0, %eax
    leave
    ret
    .cfi_endproc
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.4.3-4ubuntu5.1) 4.4.3"
    .section    .note.GNU-stack,"",@progbits

int i-4(%rbp)int jです-8(%rbp)。ご覧のとおりint j、再割り当てなどではありません。

于 2013-05-26T17:11:22.477 に答える
1

変数は一度だけ作成されると思いますが、私は気にしませんし、作成する必要もないと思います。

これはおそらく、ユーザー側での事前最適化 (または不要な最適化) の例です。ループ内で変数を宣言することによって生じる潜在的な非効率性は非常に小さく、さまざまな場所で変数を宣言してコードを「最適化」しても、プログラムの全体的な実行時間とメモリ使用量にほとんど影響を与えません。

アルゴリズムを最適化し、効率的なデータ構造を見つけることに時間を費やすことを検討してください。これにより、時間をより有効に活用できる可能性があります。

于 2013-05-26T17:13:33.277 に答える
0

自分で試してみませんか?

class foo {
public:
    foo () { std::cout << "Construct\n"; }
    ~foo () { std::cout << "Destruct\n"; }
    };

int main () {
    for ( int i = 0; i < 10; ++i ) {
        foo f;
    }

    return 0;
}

fループのたびに for のコンストラクタ (およびデストラクタ!) が呼び出されることがわかります。したがって、あなたの質問に対する答えは、「はい、変数はループのたびに再作成されます」です。

あなたの例に戻ると、何もしないコンストラクタとデストラクタを持つ int を宣言しています。そのため、ループ内で int を宣言してもパフォーマンスが低下することはありません。

于 2013-05-26T17:11:20.343 に答える
0

今日のコンパイラは、そのようなことを最適化するにはあまりにも強力です。気にせず、ご都合に合わせてご利用ください。時期尚早の最適化は、より悪質です。

于 2013-05-26T17:10:26.800 に答える