Tell about exception throwing in constructors and destructors.
sobes.tech AI
Answer from AI
Throwing an exception in a constructor can lead to resource leaks if some objects or resources inside the constructor were successfully allocated before the exception was thrown, and the corresponding destructor is not called. To prevent leaks, it is recommended to use RAII (Resource Acquisition Is Initialization), for example with smart pointers or wrapper classes that guarantee resource release upon scope exit.
Throwing an exception in a destructor leads to undefined behavior. If the destructor is called as a result of another exception (stack unwinding), and it itself throws an unhandled exception, the program will terminate via std::terminate. According to the C++ standard, destructors should be noexcept.
#include <iostream>
#include <memory> // For std::unique_ptr
struct Resource {
Resource() { std::cout << "Resource acquired\n"; }
~Resource() { std::cout << "Resource released\n"; }
};
struct BadConstructor {
Resource res; // Resource will be allocated before throwing an exception
BadConstructor() {
std::cout << "BadConstructor constructor\n";
throw std::runtime_error("Error in constructor"); // Throwing an exception
// Resource destructor will not be called if exception is thrown before constructor finishes
}
~BadConstructor() noexcept { // Destructors should be noexcept
std::cout << "BadConstructor destructor\n";
}
};
struct GoodConstructor {
std::unique_ptr<Resource> res; // Using smart pointer for RAII
GoodConstructor() : res(std::make_unique<Resource>()) {
std::cout << "GoodConstructor constructor\n";
// Now, if an exception is thrown, unique_ptr guarantees calling Resource destructor upon scope exit
// throw std::runtime_error("Error in constructor");
}
~GoodConstructor() noexcept {
std::cout << "GoodConstructor destructor\n";
}
};
struct BadDestructor {
BadDestructor() { std::cout << "BadDestructor constructor\n"; }
~BadDestructor() {
std::cout << "BadDestructor destructor\n";
// Throwing an exception from destructor is not allowed, especially during unwind
// throw std::runtime_error("Error in destructor");
}
};
int main() {
// Example with constructor (will lead to resource leak without RAII)
try {
// BadConstructor bc; // Uncomment to demonstrate leak
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << "\n";
}
// Example with good constructor (uses RAII)
try {
// GoodConstructor gc; // Uncomment to demonstrate, no leak will occur
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << "\n";
}
// Example with destructor (can lead to std::terminate)
try {
// BadDestructor bd; // Uncomment to see potential terminate
// throw std::runtime_error("Another exception"); // Exception that causes unwind
} catch (const std::exception& e) {
std::cout << "Caught exception: " << e.what() << "\n";
}
return 0;
}
Summary table:
| Place of exception throw | Potential issues | Recommended solution |
|---|---|---|
| Constructor | Resource leak | Use RAII (smart pointers, wrappers) |
| Destructor | Undefined behavior, std::terminate during unwind |
Destructors should be noexcept, avoid throwing exceptions |