As an example:
class dbconnection{ public : ... static DBConnection create (); void close ();}; // This class is responsible for database connections. // to prevent users from forgetting to close this database connection, It's easy to remember to define an auxiliary class: class dbcon{ Span style= "color: #0000ff;" >public :.. ~dbcon () {dbc.close ();} private : DBConnection DBC;}
Close if the call succeeds, there is no problem. But if the call causes an exception, the Dbconn destructor propagates the exception, causing unpredictable consequences.
Exceptions that occur in destructors are usually resolved in two ways:
End of Exception: (This prevents the damage caused by ambiguous behavior)
dbconn::~dbconn () { try{
Dbc.close ();
}catch(...) { std:abort (); } }
or swallow the exception:
dbconn::~Dbconn ()
{ try{ dbc.close (); } Catch (...) { // make a running record indicating the failure of the call } }
A better solution is to give dbconn himself a close function, and then the user does not own close in the case of using the above approach, which gives the user a chance to deal with the exception:
classdbconn{ Public: ... voidClose () {db.close (); Close=true; } ~dbconn () {if(Close = =false){ Try{
Dbc.close ();
}Catch(...) {Std::abort (); } } } Private: BOOLClose; DBConnection DBC;};
Summary: Destructors should never spit out exceptions, and if a function called by a destructor might throw an exception, the destructor should catch them and then swallow them, as the previous program did. and if the customer should react to an exception thrown during the operation of an action function, then class should provide a normal function to do this, like close above. The final destructor will be further improved.
Clause 8: Do not let an exception escape the destructor