11
struct MemBlock {

    char mem[1024];

    MemBlock operator*(const MemBlock &b) const {

        return MemBlock();
    }

} global;

void foo(int step = 0) {

    if (step == 10000)
    {
        global = global * MemBlock();
    }
    else foo(step + 1);
}

int main() {

    foo();
    return 0;
}

プログラム受信信号 SIGSEGV、セグメンテーション違反。0x08048510 in foo (step=4000) at t.cpp:12 12 void foo(int step = 0) {

MemBlock() インスタンスはまだ呼び出されていませんが、大量のスタック メモリを消費しているようです (gdb 情報を確認してください)。

代わりに使用global = global * globalすると、プログラムは正常に終了します。

内部のメカニズムを説明できる人はいますか?

4

1 に答える 1

15

コンパイラは、内の制御フローに関係なく、MemBlockへの各呼び出しでインスタンスのスタック スペースを予約しています。これは、関数内でスタック ポインターを繰り返し調整する必要がないようにするための一般的な最適化です。代わりに、コンパイラーは必要な最大スタック・スペースを計算し、関数への入り口でその量だけスタック・ポインターを調整します。foofoo

ご覧のとおり、これにより、実際には使用しないオブジェクト用に予約されたスタック スペースが失われます。答えは、そうしないことです。特定のブランチ内でフットプリントの大きいオブジェクトのみを使用している場合は、それらのブランチを独自の関数に分離します。

ちなみに、古いバージョンの C では、すべての関数スコープ変数を関数の先頭で宣言する必要があったのはこのためです。これにより、関数が必要とするスタック スペースの量をコンパイラが簡単に判断できるようになります。

于 2012-07-20T12:29:05.747 に答える