Назад к вопросам
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;
}