Sobes.tech
Middle+

In what situations do destructors not get called when exceptions occur?

sobes.tech AI

Answer from AI

Destructors of local objects are called during stack unwinding when an exception is thrown. However, there are situations where a destructor is not called:

  • When calling std::abort() or std::terminate(). These functions terminate the program immediately, without the usual cleanup and stack unwinding.
  • In case of double exception (double fault). If a second exception occurs during the handling of the first exception (in a catch block or during stack unwinding), the standard library calls std::terminate(), which leads to immediate program termination without calling destructors for objects that have not yet been destroyed.
  • When using raw pointers and references. Destructors are only called for objects created on the stack or dynamically (using new) and managed by smart pointers or manual delete. If an object is allocated dynamically and not managed, and an exception occurs before explicit delete, the destructor is not called.
  • When exiting a function using std::exit(). This function terminates the program, calling registered atexit functions, but does not call destructors for local automatic objects.
#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"); // Throw exception
    // obj will be destroyed during stack unwinding
}

void another_dangerous_function() {
    MyObject obj;
    try {
        throw std::runtime_error("First error");
    } catch(...) {
        std::cout << "Handling first error..." << std::endl;
        throw; // Rethrow - destructor of obj will be called
    }
}

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"); // Double exception - std::terminate(), destructor not guaranteed for 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 (may lead to termination)..." << std::endl;
    try {
        double_exception(); // May call std::terminate()
    } catch(const std::exception& e) {
        std::cerr << "Caught exception: " << e.what() << std::endl;
    }

    // When using std::abort() or std::exit(), destructors of local objects (created before the call) are not called
    // std::abort();
    // std::exit(0);

    return 0;
}