Item 8: Prevent exceptions from leaving destructors
Concept
Destructors should never emit exceptions. If a destructor calls a function that might throw, the destructor should catch any exceptions and either swallow them or terminate the program. This is because if an exception is already active (stack unwinding) and a destructor emits a second exception, C++ calls std::terminate. If clients need to react to an exception thrown during an operation, the class should provide a regular (non-destructor) function that performs the operation.
Code Example
class DBConn {
public:
// Provide a way for clients to handle errors
void close() {
db.close();
closed = true;
}
~DBConn() {
if (!closed) {
try {
db.close(); // last-ditch attempt
} catch (...) {
// Log the failure
// Option 1: std::abort() if we can't continue
// Option 2: swallow the exception (document this!)
}
}
}
private:
DBConnection db;
bool closed = false;
};
// Client code can handle errors explicitly:
DBConn dbc(DBConnection::create());
dbc.close(); // Client gets a chance to react to errors
// Destructor serves only as a backup
Things to Remember
- Destructors should never emit exceptions. If functions called in a destructor may throw, the destructor should catch any exceptions, then swallow them or terminate the program.
- If class clients need to be able to react to exceptions thrown during an operation, the class should provide a regular (non-destructor) function that performs the operation.