SCOPE_EXIT implementation I'm a fanboy of the Boost library and I've used Boost's components extensively in my C++03 project. The team decided to merge several pieces of code including my project. I will get the C++14 environment, but I have to drop the Boost library, so I'd like to replace BOOST_SCOPE_EXIT with a modern C++ technique.

Here is SCOPE_EXIT's implementation, with a short example:

#include &lt;cstdio&gt;
#include &lt;cstdlib&gt;
#include &lt;memory&gt;

template &lt;typename Lambda&gt;
class ScopeGuard
{
public:
    ScopeGuard(const Lambda&amp; func)
        : committed_(false), valid_(true), rollbackFunc_(func) {}

    ~ScopeGuard() noexcept
    {
        if (valid_ &amp;&amp; !committed_)
            rollbackFunc_();
    }

    ScopeGuard(const ScopeGuard&amp;) = delete;
    ScopeGuard&amp; operator=(const ScopeGuard&amp;) = delete;

    ScopeGuard(ScopeGuard&amp;&amp; other)
        : committed_(other.committed_), valid_(other.valid_), rollbackFunc_(other.rollbackFunc_)
    {
        other.valid_ = false;
    }

    ScopeGuard&amp; operator=(ScopeGuard&amp;&amp; other)
    {
        committed_ = other.committed_;
        valid_ = other.valid_;
        rollbackFunc_ = other.rollbackFunc_;
        other.valid_ = false;
        return *this;
    }

    void commit() const { committed_ = true; }

private:
    mutable bool committed_;
    bool valid_;
    Lambda rollbackFunc_; 
};

template &lt;typename Lambda&gt;
ScopeGuard&lt;Lambda&gt; makeScopeGuard(Lambda&amp;&amp; func)
{
    return ScopeGuard&lt;Lambda&gt;(func);
}


#define MY_CONCATENATE_NX(A, B) A ## B
#define MY_CONCATENATE(A, B) MY_CONCATENATE_NX(A, B)

#define SCOPE_EXIT(f) auto MY_CONCATENATE(EXIT, __LINE__) = makeScopeGuard(f);


int foo(const char*) noexcept;
bool bar(int) noexcept;
void baz(int) noexcept;

int main() {
    int f = foo("/dev/random");
    if (!f)
    {
        return EXIT_FAILURE;
    }
    SCOPE_EXIT([f](){ baz(f); })
    int b = 1;
    bar(b);
    // baz(f)

    return EXIT_SUCCESS;
}


Godbolt gcc 7.2 -std=c++14 -O2

VS2017 -W4 /EHsc /O2

gcc's assembly is pretty short, however MSVC's assembly is so long (about 70 lines) and I can't understand what's going on. (I am not familiar with the Windows environment.)

Did I miss something, or is it a bad optimization of MSVC?
Move semantics:

The makeScopeGuard() function accepts the lambda by r-value ref; but passes a normal ref to the constructor of ScopeGuard.

template &lt;typename Lambda&gt;
ScopeGuard&lt;Lambda&gt; makeScopeGuard(Lambda&amp;&amp; func)
{
    return ScopeGuard&lt;Lambda&gt;(func);
}


You should either update ScopeGuard to take the function by r-value ref or change the makeScopeGuard() take a normal ref (to be consistent).

Personally I would pass the r-value ref through to the ScopeGuard.

template &lt;typename Lambda&gt;
ScopeGuard&lt;Lambda&gt; makeScopeGuard(Lambda&amp;&amp; func)
{
    return ScopeGuard&lt;Lambda&gt;(std::move(func)); // Need the move here
                                                // a named value is not an r-value ref.
}


Also need to update ScopeGuard

ScopeGuard(Lambda&amp;&amp; func)
    : committed_(false)               // Please one line per variable
                                      // Just like in normal code
                                      // were you declare one variable per line.
    , valid_(true)
    , rollbackFunc_(std::move(func))  // Need the move again.
{}


No Except

Normally the move operators are marked noexcept. Unless you have a good reason not to I would continue that norm.

ScopeGuard(ScopeGuard&amp;&amp; other) noexcept
ScopeGuard&amp; operator=(ScopeGuard&amp;&amp; other) noexcept


Move by swapping.

The easiest way to move something is to swap it.

// Now we could implement this with a swap.
// But this seems trivial enough So this is fine.
ScopeGuard(ScopeGuard&amp;&amp; other) noexcept
    : committed_(other.committed_)        // One variable per line please.
    , valid_(other.valid_)
    , rollbackFunc_(other.rollbackFunc_)
{
    // Disabled the moved from.
    other.valid_ = false;
}

ScopeGuard&amp; operator=(ScopeGuard&amp;&amp; other) noexcept
{
    // Here we are doing a copy (why not invoke the copy constructor)?
    // Followed by marking it `false`.
    committed_ = other.committed_;
    valid_ = other.valid_;
    rollbackFunc_ = other.rollbackFunc_;
    other.valid_ = false;
    return *this;
}


I would write like this:
I personally think it is easier to read like this.

ScopeGuard(ScopeGuard&amp;&amp; other) noexcept
    : committed_(false)
    , valid_(false)
    , rollbackFunc_([](){})
{
    swap(other);
}

ScopeGuard&amp; operator=(ScopeGuard&amp;&amp; other) noexcept
{
    swap(other);
    other.valid_ = false;
    return *this;
}

void swap(ScopeGuard&amp; other) noexcept
{
    using std::swap;
    swap(committed_,    other.committed_);
    swap(valid_,        other.valid_);
    swap(rollbackFunc_, other.rollbackFunc_);
}


Abuse of mutable

mutable bool committed_;


Not sure I like this. Is this because you have a const value and want to get around the constness of the object?

Mutable objects are meant to represent objects that are not part of the full state of the object. i.e. a cached or computed part of the state that can be re-calculated.

committed_ is very much part of the objects main state. So I would not mark it mutable.

That of course means you have to remove the const off the commit method.

void commit()       { committed_ = true; }
              ^^^^^ removed const


It is changing the state so its not really a const method.

Commit

There seems to be no way to call commit!!!

SCOPE_EXIT([f](){ baz(f); })

// how do I call commit on the above?
// I could use my editor to find the line number, but thats very fragile.
// And probably not what you intended to do.


bar(5); // It worked no exception
// So here I would expect to call commit.


If you can not call commit() then you should remove it from the class.

I would just get rid of the macors. Then your users can do:

auto guard = makeScopeGuard([](){revertStuff();}
// DO WORK HERE

// WORK DONE
guard.commit(); // no exceptions so we commit and don't need to revert.


An example working with correct move semantics fo the pedants:

#include &lt;cstdio&gt;
#include &lt;cstdlib&gt;
#include &lt;memory&gt;
#include &lt;functional&gt;
#include &lt;iostream&gt;


class ScopeGuard
{
public:
    ScopeGuard(std::function&lt;void()&gt;&amp;&amp; func)
        : committed_(false)
        , valid_(true)
        , rollbackFunc_(std::move(func))
    {}

    ~ScopeGuard() noexcept
    {
        if (valid_ &amp;&amp; !committed_)
            rollbackFunc_();
    }

    ScopeGuard(const ScopeGuard&amp;) = delete;
    ScopeGuard&amp; operator=(const ScopeGuard&amp;) = delete;

    ScopeGuard(ScopeGuard&amp;&amp; other) noexcept
        : committed_(false)
        , valid_(false)
    {
        swap(other);
    }

    ScopeGuard&amp; operator=(ScopeGuard&amp;&amp; other) noexcept
    {
        swap(other);
        return *this;
    }

    void swap(ScopeGuard&amp; other)
    {
        using std::swap;
        swap(committed_,    other.committed_);
        swap(valid_,        other.valid_);
        swap(rollbackFunc_, other.rollbackFunc_);
    }

    void commit() const { committed_ = true; }

private:
    mutable bool          committed_;
    bool                  valid_;
    std::function&lt;void()&gt; rollbackFunc_;␣
};

ScopeGuard makeScopeGuard(std::function&lt;void()&gt;&amp;&amp; func)
{
    return ScopeGuard(std::move(func));
}


#define MY_CONCATENATE_NX(A, B) A ## B
#define MY_CONCATENATE(A, B) MY_CONCATENATE_NX(A, B)

#define SCOPE_EXIT(f) auto MY_CONCATENATE(EXIT, __LINE__) = makeScopeGuard(f);

int foo(const char*) noexcept {std::cout &lt;&lt; "food\n";return 0;}
bool bar(int) noexcept {std::cout &lt;&lt; "bar\n";return true;}
void baz(int) noexcept {std::cout &lt;&lt; "baz\n";}

int main() {
    int f = foo("/dev/random");
    if (!f)
    {
        return EXIT_FAILURE;
    }
    SCOPE_EXIT([f](){ baz(f); })
    int b = 1;
    bar(b);
    baz(f)    
}