Назад к вопросам
Middle+
91
questionbank
В каких ситуациях деструкторы не вызываются при возникновении исключений?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Деструкторы локальных объектов вызываются при раскрутке стека во время обработки исключения. Однако есть ситуации, когда деструктор не вызван:
- При вызове
std::abort()илиstd::terminate(). Эти функции завершают программу немедленно, без обычной процедуры очистки и раскрутки стека. - При двойном выбросе исключения (двойной ошибке). Если внутри обработчика исключения (блока
catch) или во время раскрутки стека при обработке первого исключения возникает второе исключение (std::uncaught_exceptions() > 0), стандартная библиотека вызываетstd::terminate(), что приводит к немедленному завершению программы без вызова деструкторов для объектов, которые еще не были уничтожены. - При использовании необработанных указателей и ссылок. Деструкторы вызываются только для объектов, созданных на стеке или динамически (с помощью
new) и управляемых умными указателями или ручнымdelete. Если объект выделен динамически и не управляется, а исключение происходит до явногоdelete, деструктор не вызывается. - При выходе из функции с помощью
std::exit(). Эта функция завершает программу, вызывая зарегистрированные функцииatexit, но не вызывает деструкторы для локальных автоматических объектов.
#include <iostream>
#include <exception>
struct MyObject {
MyObject() { std::cout << "MyObject constructed" << std::endl; }
~MyObject() { std::cout << "MyObject destroyed" << std::endl; }
};
void dangerous_function() {
MyObject obj;
throw std::runtime_error("An error occurred"); // Выброс исключения
// obj будет уничтожен при раскрутке стека
}
void another_dangerous_function() {
MyObject obj;
try {
throw std::runtime_error("First error");
} catch(...) {
std::cout << "Handling first error..." << std::endl;
throw; // Rethrow - деструктор obj будет вызван
}
}
void double_exception() {
MyObject obj;
try {
throw std::runtime_error("First error");
} catch(...) {
std::cout << "Handling first error..." << std::endl;
throw std::runtime_error("Second error"); // Двойное исключение - std::terminate(), деструктор не гарантирован для obj
}
}
int main() {
try {
dangerous_function();
} catch(const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
try {
another_dangerous_function();
} catch(const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
std::cerr << "Demonstrating double exception (可能會導致終止)..." << std::endl;
try {
double_exception(); // Может вызвать std::terminate()
} catch(const std::exception& e) {
std::cerr << "Caught exception: " << e.what() << std::endl;
}
// При использовании std::abort() или std::exit() деструкторы локальных объектов (созданных до вызова) не вызываются
// std::abort();
// std::exit(0);
return 0;
}