22 Jan 2024 • C++ tricks: defer

I was writing another tricks post and was shocked to find I hadn't already posted this. It's super useful! C++ purists would call it heresy and tell you to use RAII, in practice I've found RAII gets in the way as much as it helps which is annoying and no good.

Credit to either Jonathan Blow and Ignacio CastaƱo, since this is either lifted from jblow's MSVC finder or this blog post.

// you probably have these macros already
#define CONCAT_HELPER( a, b ) a##b
#define CONCAT( a, b ) CONCAT_HELPER( a, b )
#define COUNTER_NAME( x ) CONCAT( x, __COUNTER__ )

template< typename F >
struct ScopeExit {
    ScopeExit( F f_ ) : f( f_ ) { }
    ~ScopeExit() { f(); }
    F f;
};

struct DeferHelper {
    template< typename F >
    ScopeExit< F > operator+( F f ) { return f; }
};

#define defer [[maybe_unused]] const auto & COUNTER_NAME( DEFER_ ) = DeferHelper() + [&]()

[[maybe_unused]] is to shut clang up. Use it like so:

void f() {
    void * p = malloc( 1 );
    defer { free( p ); };
}