Sobes.tech
Middle+
142
questionbank

В каких ситуациях деструкторы не вызываются при возникновении исключений?

Answer from AI

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;
}