Finally in C++

Tamara Wijsman picture Tamara Wijsman · Dec 24, 2008 · Viewed 23.1k times · Source

Is this a good way to implement a Finally-like behavior in standard C++? (Without special pointers)

class Exception : public Exception
    { public: virtual bool isException() { return true; } };

class NoException : public Exception
    { public: bool isException() { return false; } };


Object *myObject = 0;

try
{
  // OBJECT CREATION AND PROCESSING
  try
  {
    myObject = new Object();

    // Do something with myObject.
  }

  // EXCEPTION HANDLING
  catch (Exception &e)
  {
    // When there is an excepion, handle or throw,
    // else NoException will be thrown.
  }

  throw NoException();
}

// CLEAN UP
catch (Exception &e)
{
  delete myObject;

  if (e.isException()) throw e;
}
  1. No exception thrown by object -> NoException -> Object cleaned up
  2. Exception thrown by object -> Handled -> NoException -> Object cleaned up
  3. Exception thrown by object -> Thrown -> Exception -> Object cleaned up -> Thrown

Answer

David Norman picture David Norman · Dec 24, 2008

The standard answer is to use some variant of resource-allocation-is-initialization abbreviated RAII. Basically you construct a variable that has the same scope as the block that would be inside the block before the finally, then do the work in the finally block inside the objects destructor.

try {
   // Some work
}
finally {
   // Cleanup code
}

becomes

class Cleanup
{
public:
    ~Cleanup()
    {
        // Cleanup code
    }
}

Cleanup cleanupObj;

// Some work.

This looks terribly inconvenient, but usually there's a pre-existing object that will do the clean up for you. In your case, it looks like you want to destruct the object in the finally block, which means a smart or unique pointer will do what you want:

std::unique_ptr<Object> obj(new Object());

or modern C++

auto obj = std::make_unique<Object>();

No matter which exceptions are thrown, the object will be destructed. Getting back to RAII, in this case the resource allocation is allocating the memory for the Object and constructing it and the initialization is the initialization of the unique_ptr.