Переполнение стека: дублирование временного выделения в пространстве стека?

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 в foo (шаг = 4000) при t.cpp: 12 12 void foo (int step = 0) {

Кажется, что экземпляр MemBlock() стоит много памяти стека, хотя он еще не был вызван (проверьте информацию gdb).

И когда я использую global = global * global вместо этого, программа выйдет нормально.

Кто-нибудь может объяснить внутренний механизм?

Ответ 1

Компилятор резервирует пространство стека для экземпляра MemBlock при каждом вызове foo, независимо от потока управления внутри foo. Это обычная оптимизация, чтобы не допустить повторной настройки указателя стека внутри этой функции. Вместо этого компилятор вычисляет максимальное требуемое пространство стека и при входе в функцию настраивает указатель стека на эту сумму.

Как вы заметили, это приводит к потере пространства стека, зарезервированного для объектов, которые вы на самом деле не используете. Ответ заключается в том, чтобы не делать этого; если вы используете только некоторые объекты с большими отпечатками в определенных ветвях, тогда отделите эти ветки на свою собственную функцию.

Кстати, именно поэтому архаичные версии C требовали, чтобы все переменные-функции были объявлены в верхней части функции; так что компилятор может легко определить, сколько пространства стека требуется функции.