Стандарт определяет три способа завершения выполнения программы на C ++:
- Возврат из
main
. Объекты с автоматическим хранением (function-local) уже уничтожены. Объекты со статическим хранилищем (глобальные, статические, функциональные) будут уничтожены.
std::exit
от <cstdlib>
. Объекты с автоматическим хранением НЕ уничтожены. Объекты со статическим хранилищем будут уничтожены.
std::abort
из <cstdlib>
. Объекты с автоматическим и статическим хранением НЕ уничтожены.
Также имеет значение std::terminate
из <exception>
. Поведение terminate
можно заменить с помощью std::set_terminate
, но terminate
всегда должно "завершать выполнение программы", вызывая abort
или какую-либо аналогичную для реализации альтернативу. По умолчанию это просто { std::abort(); }
.
C ++ будет вызывать std::terminate
всякий раз, когда выдается исключение, и C ++ не может разумно выполнить разматывание стека. Например, исключение из деструктора, вызываемого разматыванием стека, или исключение из статического конструктора или деструктора объекта хранения. В этих случаях (больше) разматывание стека не выполняется.
C ++ также вызовет std::terminate
, если соответствующий обработчик catch
не найден. В этом единственном случае C ++ может опционально раскрутиться до main
перед вызовом terminate
. Так что ваш пример может иметь разные результаты с другим компилятором.
Так что, если вы правильно используете RAII, оставшиеся шаги для «утечки» вашей программы:
- Избегайте
std::abort
.
- Либо избегайте
std::exit
, либо избегайте всех объектов со статической продолжительностью хранения.
- Поместите обработчик
catch (...)
в main
и убедитесь, что в нем или после него не происходит выделений или исключений.
- Избегайте других ошибок программирования, которые могут вызвать
std::terminate
.
- (В некоторых реализациях функции, скомпилированные с помощью компилятора C, действуют так, как будто у них есть пустая спецификация
throw()
в C ++, что означает, что исключения не могут быть "пропущены" через них, даже если у них нет деструкторов для вызова.)