Finally, No

By | 2013-07-04

Why doesn’t C++ have a finally block? Here’s some Java.

void userFunction() {
    f = new Resource();
    f.open();
    try {
        // might throw
        buffer = f.read();
    } finally {
        f.close();
    }
    useBuffer(buffer);
}

It’s tempting, after you’ve had a finally for a while to think that it’s necessary for proper resource management in the face of exceptions. We’ve not had to free up f because Java’s garbage collection will sort out the memory (although I’m not a fan of that).

You might see something like this in C++ to work around the lack of finally:

void userFunction() {
    Resource *f = new Resource;
    try {
        buffer = f->read();
    } catch( ... ) {
        f->close();
        delete f;
        throw;
    }
    useBuffer(buffer);
}

Code like this is bad.

Object oriented management of resources should be done by never using your resource in this, so-called, “naked” manner. To be fair it’s not this code that’s wrong, it’s the code for Resource, or possibly the code that hasn’t been written to correctly manage a Resource.

The point of object oriented languages is to create new types, types that are intelligent. In particular, we should make use of the principle RAII, resource acquisition is initialisation. By implication then, resource release is deinitialisation.

class unique_resource {
  public:
    unique_resource() {
        resource = new Resource;
        resource->open();
    }
    ~unique_resource() {
        resource->close();
        delete resource;
    }
    Resource &operator() { return *resource; }
  protected:
    Resource *resource;
};

// ... elsewhere in the forest ...

void userFunction() {
    unique_resource f;
    buffer = f().read();
}

What matters here is no try..except and no finally in userFunction(). They’re all unnecessary because, should there be an exception, f will be destructed automatically before the exception starts propagating back up the call stack.

So, should you find yourself wishing C++ had a finally, or for that matter, should you find yourself using finally in Java; you’ve probably already done something wrong – resources should be managed in an object, and they should manage themselves by virtue of the language features. You can’t do this in Java, because of it’s soft support for destructors (finalize() is about the nearest, but that comes with caveats).

This principle applies even further; using new outside of a constructor is indicative that you’ve made a design mistake. In really simple cases C++11 can automatically supply you the object you should have written yourself with the unique_ptr class.

Leave a Reply