c++exceptiondestructorraiieffective-c++

Understanding the destructor call in item 8 of Effective C++, Third edition


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?


Solution

  • 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.