The final macro

The problem

Cleaning up resources is hard. One has to keep track of all allocated resources and make sure to free each one on each error path. The difficulty is compounded, some say, with exceptions, which can make error paths non-obvious. Traditionally, C++ programmers use RAII wrappers (e.g. unique_ptr
and CComPtr) to automatically clean up resources --- but it's inconvenient to create a new type for each possible cleanup activity. In exceptional code in particular, we're often forced to either create yet another RAII type, or duplicate cleanup code in the success and exception-rethrowing paths. It becomes messy quickly.

The solution

Other languages provide facilities (like finally and unwind-protect) to delay the execution of bits of code until the current task is completed; it's natural to clean up resources in finally blocks. C++ has never had finally blocks, but the latest language features allow us to create them ourselves. I've always said that the wondering thing about C++ is its ability to create very powerful, but also easy-to-use abstractions. It's powerful enough to implement features other languages have to have built in. Let's look at an example:

Code Output
 voidfoo (int n){    printf ("foo %d\n", n);}voidbar (){    int* x = new int (5);    FINALLY (foo (*x), delete x);    printf ("Hello, world!\n");    FINALLY ({        if (x) {            printf ("Look, a statement!\n");        }    });    printf ("Second line\n");}voidqux (){    FINALLY (printf ("After throw\n"));    printf ("throwing\n");    throw 42;}int main (){    bar ();    printf ("bar returned\n");    try {        qux ();    } catch (int) {        printf ("caught exception\n");    }        printf ("qux returned\n");}
 Hello, world!Second lineLook, a statement!foo 5bar returnedthrowingAfter throwcaught exceptionqux returned

The code above isn't witchcraft. It's standards-conforming† code. Here's the bit that makes it work:

 
#include <utility>

template<typename FunctorT>
struct FinallyUnwinder
{
    FinallyUnwinder (FunctorT Functor)
        : Functor (std::move (Functor))
    {}

    FinallyUnwinder (FinallyUnwinder&& Other)
        : Functor (std::move (Other.Functor))
    {}

    ~FinallyUnwinder ()
    { this->Functor (); }
    
    private:
    FinallyUnwinder (const FinallyUnwinder& other);
    FinallyUnwinder& operator=(const FinallyUnwinder& other);
    FunctorT Functor;
};

template<typename FunctorT>
typename FinallyUnwinder<FunctorT>
Finally (FunctorT Functor)
{
    return FinallyUnwinder<FunctorT> (std::move (Functor));
}

#define UTX_CAT2(a,b) a ## b
#define UTX_CAT(a,b) UTX_CAT2 (a, b)
#define UTX_GENSYM(ar) UTX_CAT (ar, __LINE__)

#define FINALLY(...)                          \
    auto UTX_GENSYM (utx_finally) =           \
        Finally ([&] () { __VA_ARGS__ ; });

This code relies on variadic macros, lambda functions, and move constructors, all of which are very recent features.

To see how it all fits together, let's look at the preprocessed version of one of the lines above:

 
auto utx_finally65 = Finally ([&] () { printf ("After throw\n") ; });;

Here, we're creating a lambda functor object, capturing all variables from the parent function by their addresses (which is fine, because this lambda will never run after its parent function returns), and stashing the result away in an automatic variable; its type is specific to the functor being assigned, and its name is created via macro magic. The compiler understands what's going on and can inline this entire process, producing code that's just as efficient as the hand-coded equivalent.

Conclusion

Using powerful primitives built into C++, we can create new expressive constructs, and we don't need to give up any performance in the process. The above macro, while tricky to implement, is an convenient alternative to explicit RAII. While previous attempts to enjoyed some success, it's only with C++11 that we're able to provide a natural and convenient syntax.

Notes

† - variadic macros are technically supported in C99, not C++, but support for variadic macros in C++11 compilers is universal.