In Effective C++, by Scott Meyers, item 8, there is a suggestion to wrap (using RAII) an object that has a close
method that may throw, to automatically call close
in the destructor, but since exceptions should not leave destructor, there is another suggestion to wrap the close method to allow the user to handle the exception himself.
class DBConn
{
public:
//...
void close() // Exposed to allow users to react to exceptions
{
db.close();
closed = true;
}
~DBConn() // Use RAII to automatically call close
{
if (!closed) // This is not set to true if close was called and the user has handled the exception
{
try {
db.close();
}
catch(...)
{
// terminate or swallow the exception
}
}
}
private:
DBConnection db; // Object with just a close method that may throw
bool closed;
};
If one calls DBConn::close
and that method throws, then closed
is never set to true
and the destructor of DBConn
will again attempt to call close
.
Is this a bug, intended, left out for space reasons?
It is hard to say what the author's intention was, but I think it's all just fine. If db
was not closed then closed
should not be set to true
.
Later attempting again to close the db
in the destructor either succeeds, or fails and the exception is caught in the destructor. No problem with that, if DBConnection::close
gives a strong exception guarantee: If an exception is thrown, the state of db
is as if before calling close
.
Only if attempting to close the database is expensive and you want to try it only once, the code would need a fix. Though, the crucial point of the example is that exceptions shall not leave the destructor.