RAII и стек раскручивается

До сих пор мои представления о "переплетении" (из-за отсутствия лучшего слова) RAII и раскручивания стека были / были (если не полностью) неправильными. Насколько я понимаю, использование RAII защищает от любых / всех утечек ресурсов, даже тех, которые могут быть вызваны необработанными исключениями.

Однако написание этой тестовой программы и впоследствии наткнувшись на эту статью / документацию, заставило меня осознать, что раскручивание стека вызовет только то, что освобождение ресурса с поддержкой RAII сработает только для автоматических в блоке try, а не для автоматических в, скажем, внешних / других областях.,

Я прав в этом (новом) понимании? Или есть еще нюансы, которые я еще не уловил? Любой гуру хочет присоединиться? Указатели на любые хорошие рецензии / анализы / объяснения (раскручивания стека) были бы полезны / оценены…

3 ответа

Решение

Из стандарта C++03, §15.3/9:

Если в программе не найден соответствующий обработчик, вызывается функция terminate (); действительно ли стек разматывается до того, как этот вызов terminate () определяется реализацией (15.5.1).

§15.5.1 / 1:

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

§15.5.1 / 2:

В таких случаях,

void terminate ();

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

Вы правы, что "раскручивание стека" происходит на пути от throw some_exception в catch(some_exception), Если ваше исключение никогда не достигнет цели, мы не знаем, что произойдет.

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

Стандарт определяет три способа прекращения выполнения программы на C++:

  • Вернуться из main, Объекты с автоматическим хранением (function-local) уже уничтожены. Объекты со статическим хранилищем (глобальные, статические, функциональные) будут уничтожены.
  • std::exit от <cstdlib>, Объекты с автоматическим хранением НЕ уничтожаются. Объекты со статическим хранилищем будут уничтожены.
  • std::abort от <cstdlib>, Объекты с автоматическим и статическим хранением НЕ уничтожаются.

Также актуальным является std::terminate от <exception>, Поведение terminate можно заменить с помощью std::set_terminate, но terminate всегда должен "прекратить выполнение программы", вызвав abort или некоторая аналогичная, зависящая от реализации альтернатива. По умолчанию просто { std::abort(); },

С ++ будет звонить std::terminate всякий раз, когда выдается исключение, и C++ не может разумно выполнить раскрутку стека. Например, исключение из деструктора, вызываемого разматыванием стека, или исключение из статического конструктора или деструктора объекта хранения. В этих случаях (больше) разматывание стека не выполняется.

C++ также вызовет std::terminate когда совпадение catch обработчик не найден. В этом единственном случае C++ может по желанию main перед звонком terminate, Так что ваш пример может иметь разные результаты с другим компилятором.

Так что, если вы правильно используете RAII, оставшиеся шаги для "утечки" вашей программы:

  • избежать std::abort,
  • Либо избегайте std::exit или избегайте всех объектов со статической продолжительностью хранения.
  • Положить catch (...) обработчик в mainи убедитесь, что в нем или после него не происходит никаких распределений или исключений.
  • Избегайте других ошибок программирования, которые могут вызвать std::terminate,
    • (В некоторых реализациях функции, скомпилированные с помощью компилятора C, ведут себя так, как будто они имеют C++ пустой throw() спецификация, означающая, что исключения не могут быть "пропущены" за ними, даже если у них нет деструкторов, которые можно вызвать.)
Другие вопросы по тегам