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()orstd::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
catchblock or during stack unwinding), the standard library callsstd::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 manualdelete. If an object is allocated dynamically and not managed, and an exception occurs before explicitdelete, the destructor is not called. - When exiting a function using
std::exit(). This function terminates the program, calling registeredatexitfunctions, 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;
}