On-the-fly destructors
Efficiency
The main issue with std::function&lt;void()&gt; is that it is heavy in memory usage. It comes in at a minimum of 32 bytes in G++ and (if memory serves me right) 40 bytes in VC++2015 32-bit.
See: http://coliru.stacked-crooked.com/a/9503ca27f1faded8
Solution
Don't use std::function&lt;void()&gt;.

A lightweight implementation
I promise you that we can reduce the on-scope-exit object's size to a tiny 1 byte when all we want to do is take an action at the end of a scope by using lambdas and templates.
Note: The implementation requires the &lt;utility&gt; and &lt;type_traits&gt; headers.
Step 1: Make a helper function that creates a lambda that calls a callable object.
template &lt;typename F, typename... Args&gt;
auto make_lambda( F&amp;&amp; f, Args&amp;&amp;... f_args ) noexcept
{
    // important to capture by copy to prevent argument lifetime issues
    return [=] () mutable -&gt; std::result_of_t&lt;F( Args... )&gt;
    {
        return std::forward&lt;F&gt;( f )( std::forward&lt;Args&gt;( args )... );
    };
}


This function creates a lambda that calls the argument callable. We do this so that we can store it for later use; for our use case, in a destructor so that it is called at the end of a scope.
As of C++14, the noexcept specifier is not part of a function's type, so when C++17 comes around and changes that, you'll probably want to come back to this function. See this for more information: https://stackoverflow.com/q/33589752/2296177

Step 2: A function to generate the object that calls the stored lambda in its destructor.
template&lt;class F&gt;
auto on_scope_exit( F&amp;&amp; f ) noexcept
{
    class unique_scope_exit_t final
    {
    private:
        using fn_t = decltype( make_lambda( std::move( f ) ) );

        fn_t fn_;

    public:
        ~unique_scope_exit_t()
            noexcept( noexcept( fn_() ) )
        {
            fn_(); // call it in our destructor
        }

        unique_scope_exit_t( F&amp;&amp; fn ) // can be extended for complex lambdas
            noexcept( std::is_nothrow_move_constructible&lt;fn_t&gt;::value )
            : fn_{ make_lambda( std::move( fn ) ) } // take ownership and store the lambda
        {}

        unique_scope_exit_t( unique_scope_exit_t&amp;&amp; rhs )
            noexcept( std::is_nothrow_move_constructible&lt;fn_t&gt;::value )
            : fn_{ std::move( rhs.fn_ ) }
        {}

        unique_scope_exit_t( unique_scope_exit_t const&amp; ) = delete;
        unique_scope_exit_t&amp; operator=( unique_scope_exit_t const&amp; ) = delete;
        unique_scope_exit_t&amp; operator=( unique_scope_exit_t&amp;&amp; ) = delete;
    };
    return unique_scope_exit_t{ std::move( f ) }; // we take ownership of argument 'f'
}


Having a class definition that is local to our function allows us to use the deduced type of the template type argument.
Take advantage of the &lt;type_traits&gt; header to make it optimal by declaring everything noexcept when possible.
You can provide a variadic template to the constructor in order to make full usage of make_lambda() and so that you can support complex end-of-scope actions. I leave this implementation to you, it is trivial.
The C++17 standard will guarantee copy elision for the function return.

As promised, one of our objects takes a single byte when its lambda doesn't capture anything. That is:
auto test = on_scope_exit( [] { std::cout &lt;&lt; &quot;exiting\n&quot;; } );
static_assert( sizeof( decltype( test ) ) == 1, &quot;!&quot; );

This is as it implies... the size of our generated object only takes as many bytes as it needs.
We have achieved an implementation that is both flexible and efficient (in speed and size).
Sample usage
Similar to your usage, however there are no macros involved (personal preference). You can easily wrap this in a macro if it makes you happy.
#include &lt;iostream&gt;

int main()
{
    // remember to store the call's return to prevent it from running early
    auto exit1 = on_scope_exit( [] { std::cout &lt;&lt; &quot;1\n&quot;; } );
    auto exit2 = on_scope_exit( [] { std::cout &lt;&lt; &quot;2\n&quot;; } );
    auto exit3 = on_scope_exit( [] { std::cout &lt;&lt; &quot;3\n&quot;; } );

    std::cout &lt;&lt; &quot;4\n&quot;;
    std::cout &lt;&lt; &quot;5\n&quot;;
}

Full demo: http://coliru.stacked-crooked.com/a/da1afa40ae073523

Due to comments.
Other possible implementations
As noted by Loki Astari and Nikita Kakuev, the previous implementation can increase the executable's size if it is used with many (very many) different types.
In a regular use case, I still think this is a better approach than constantly constructing and destroying 32+ bytes. For example, VC++2015's std::function&lt;void()&gt; is 40 bytes in 32-bit mode and 64 bytes in 64-bit mode.
As Nikita Kakuev points out here, make_lambda()'s signature might be over-generalized for this specific case, so it could be omitted in favour of a more succinct on_scope_exit().
The original thought was that you could make unique_scope_exit_t's constructor take a variadic template in order to allow complex end-of-scope actions by storing callables whose operator() have parameters.
If this isn't desired, we can simply remove make_lambda() and provide the following implementation of on_scope_exit() with a reduced executable size hit:
template&lt;class F&gt;
auto on_scope_exit( F&amp;&amp; f )
    noexcept( std::is_nothrow_move_constructible&lt;F&gt;::value )
{
    class unique_scope_exit_t final
    {
        F f_;

    public:
        ~unique_scope_exit_t()
            noexcept( noexcept( f_() ) )
        {
            f_();
        }

        explicit unique_scope_exit_t( F&amp;&amp; f )
            noexcept( std::is_nothrow_move_constructible&lt;F&gt;::value )
            : f_( std::move( f ) )
        {}

        unique_scope_exit_t( unique_scope_exit_t&amp;&amp; rhs )
            noexcept( std::is_nothrow_move_constructible&lt;F&gt;::value )
            : f_{ std::move( rhs.f_ ) }
        {}

        unique_scope_exit_t( unique_scope_exit_t const&amp; ) = delete;
        unique_scope_exit_t&amp; operator=( unique_scope_exit_t const&amp; ) = delete;
        unique_scope_exit_t&amp; operator=( unique_scope_exit_t&amp;&amp; ) = delete;
    };
    return unique_scope_exit_t{ std::move( f ) };
}

This provides semantics similar to a std::unique_ptr&lt;&gt; solution while making intent clear and keeping size down to what is actually used (std::unique_ptr&lt;&gt; does store a pointer of type T after all). Usage remains as before.