Что раскручивает стек?

Что раскручивает стек? Перерытый, но не мог найти поучительный ответ!

186
задан R. Martinho Fernandes 17 October 2012 в 00:33
поделиться

6 ответов

О раскручивании стека обычно говорят в связи с обработкой исключений.Вот пример:

void func( int x )
{
    char* pleak = new char[1024]; // might be lost => memory leak
    std::string s( "hello world" ); // will be properly destructed

    if ( x ) throw std::runtime_error( "boom" );

    delete [] pleak; // will only get here if x == 0. if x!=0, throw exception
}

int main()
{
    try
    {
        func( 10 );
    }
    catch ( const std::exception& e )
    {
        return 1;
    }

    return 0;
}

Здесь память, выделенная для pleak , будет потеряна при возникновении исключения, в то время как память, выделенная для s , будет должным образом освобождена с помощью std :: string деструктор в любом случае. Объекты, размещенные в стеке, "разворачиваются" при выходе из области видимости (здесь область видимости имеет функцию func .) Это делается компилятором, вставляющим вызовы деструкторов автоматических (стековых) переменных.

Это очень мощная концепция, ведущая к технологии под названием RAII , то есть Resource Acquisition Is Initialization , которая помогает нам управлять такими ресурсами, как память, соединения с базой данных, дескрипторы открытых файлов. и т. д. в C ++.

Теперь это позволяет нам предоставлять гарантии безопасности исключений .

143
ответ дан 23 November 2019 в 05:50
поделиться

В общем смысле "раскрутка" стека в значительной степени синонимична завершению вызова функции и последующему открытию стека.

Однако, особенно в случае C ++, раскрутка стека связана с тем, как C ++ вызывает деструкторы для объектов, выделенных с момента запуска любого блока кода. Объекты, которые были созданы в блоке, освобождаются в порядке, обратном их распределению.

41
ответ дан 23 November 2019 в 05:50
поделиться

Не знаю, читали ли вы это, но в статье Википедии о стеке вызовов есть достойное объяснение.

Разворачивание:

Возврат из вызванной функции выводит верхний кадр из стека, возможно, оставляя возвращаемое значение. Более общий акт снятия одного или нескольких кадров со стека для возобновления выполнения в другом месте программы называется разматыванием стека и должен выполняться при использовании нелокальных структур управления, таких как те, которые используются для обработки исключений. В этом случае стековый кадр функции содержит одну или несколько записей, определяющих обработчики исключений. При возникновении исключения стек разворачивается до тех пор, пока не будет найден обработчик, готовый обработать (поймать) тип возникшего исключения.

Некоторые языки имеют другие управляющие структуры, требующие общего разворачивания. Паскаль позволяет с помощью глобального оператора goto передавать управление из вложенной функции в ранее вызванную внешнюю функцию. Эта операция требует разворачивания стека, удаляя столько кадров стека, сколько необходимо для восстановления надлежащего контекста для передачи управления целевому оператору в рамках вложенной внешней функции. Аналогично, в языке Си есть функции setjmp и longjmp, которые действуют как нелокальные gotos. Common Lisp позволяет контролировать то, что происходит при разворачивании стека, с помощью специального оператора unwind-protect.

При применении продолжения стек (логически) разворачивается, а затем снова разворачивается вместе со стеком продолжения. Это не единственный способ реализации продолжений; например, при использовании нескольких явных стеков применение продолжения может просто активизировать его стек и намотать передаваемое значение. Язык программирования Scheme позволяет произвольным банкам выполняться в заданных точках при "разматывании" или "перематывании" стека управления, когда вызывается продолжение.

Inspection[edit]

12
ответ дан 23 November 2019 в 05:50
поделиться

Раскрутка стека - это в основном концепция C ++, касающаяся того, как объекты, выделенные стеком, уничтожаются при выходе из области действия (обычно или через исключение).

Допустим, у вас есть этот фрагмент кода:

void hw() {
    string hello("Hello, ");
    string world("world!\n");
    cout << hello << world;
} // at this point, "world" is destroyed, followed by "hello"
13
ответ дан 23 November 2019 в 05:50
поделиться

Все это относится к C ++:

Определение : Когда вы создаете объекты статически (в стеке, а не выделяете их в куче памяти) и выполняют вызовы функций, они «складываются».

При выходе из области (все, что ограничено { и } ) (используя return XXX; , достигая конца области или бросая исключение) все в этой области уничтожается (деструкторы вызываются для всего). Этот процесс уничтожения локальных объектов и вызова деструкторов называется раскручиванием стека.

У вас есть следующие проблемы, связанные с раскручиванием стека:

  1. предотвращение утечек памяти (все, что динамически выделяется, что не управляется локальным объектом и очищается в деструкторе, будет утрачено) - см. RAII , ссылка на Николая, и документация для boost :: scoped_ptr или этот пример использования boost :: mutex :: scoped_lock .

  2. Согласованность программы: в спецификациях C ++ указано, что вы никогда не должны генерировать исключение до того, как любое существующее исключение будет обработано. Это означает, что процесс раскрутки стека никогда не должен вызывать исключение (либо использовать только код, гарантированно не вызывающий деструкторы, либо окружать все деструкторы с помощью try { и } catch (...) {} ).

Если какой-либо деструктор генерирует исключение во время раскрутки стека, вы попадаете в область неопределенного поведения , что может привести к неожиданному завершению вашей программы (наиболее распространенное поведение) или завершению вселенной (теоретически возможно, но имеет на практике еще не наблюдалось).

68
ответ дан 23 November 2019 в 05:50
поделиться

Когда генерируется исключение и управление передается от блока try к обработчику, среда выполнения C ++ вызывает деструкторы для всех автоматических объектов, созданных с начала блока try. Этот процесс называется раскручиванием стека. Автоматические объекты уничтожаются в порядке, обратном их построению. (Автоматические объекты - это локальные объекты, которые были объявлены автоматически или зарегистрированы, или не объявлены статическими или внешними. Автоматический объект x удаляется всякий раз, когда программа выходит из блока, в котором объявлен x.)

Если во время построения возникает исключение. объекта, состоящего из подобъектов или элементов массива, деструкторы вызываются только для тех подобъектов или элементов массива, которые были успешно созданы до того, как было сгенерировано исключение. Деструктор для локального статического объекта будет вызываться только в том случае, если объект был успешно построен.

2
ответ дан 23 November 2019 в 05:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: