I\'ve written a small utility class for C++11 which I use as a scope guard for easier handling of exception safety and similar things.
Seems somewhat like a hack. Bu
Scope guards are definitely a good idea. I think the scope guard concept is potent tool for exception safety. If you can make a safer, cleaner version that Boost's ScopeExit using C++0x syntax, I think it would be well worth your time.
Similar to Alexandrescu's ScopeGuard and Boost's ScopeExit , the D programming language has direct syntax for this sort of thing. The D programming team thought the scope guard was a good enough idea that they added it directly to the language (ie it's not implemented in a library).
Example.
void foo( bool fail )
{
scope(exit)
{
writeln("I'm always printed");
}
scope(success) writeln("The function exited normally");
scope(error)
writeln("The function exited with an exception.");
if( fail )
throw new Exception("Die Die Die!");
}
The scope based guards aren't anything new. It's functionality can easily be replicated with a class destructor (RAII and all that). It's also possible to replace with try/finally
in C# or Java. Heck, even pthreads provides a rudimentary scope guard, called pthread_cleanup_push.
What makes scope guards so powerful is when you have multiple scope(*)
statements in the function. It scales incredibly well, as opposed to try/finally
which require super human powers to manage anything more than two.
Using Boost:
#include <boost/preprocessor/cat.hpp>
template<class Fn>
class ScopeGuardDetails {
const Fn m_fn;
public:
constexpr ScopeGuardDetails(Fn &&fn) : m_fn(fn) {}
~ScopeGuardDetails() { m_fn(); }
};
#define ScopeGuardName BOOST_PP_CAT(BOOST_PP_CAT(__scope_guard, _), BOOST_PP_CAT(BOOST_PP_CAT(__LINE__, _), __COUNTER__))
#define defer(stmt) const auto ScopeGuardName = [](const auto _fn) { \
return ScopeGuardDetails<decltype(_fn)> { std::move(_fn) }; \
}([&] { stmt });
Usage:
if (gdiplus::GdiplusStartup(&token, &startupInput, nullptr) == Gdiplus::Ok) {
defer({
gdiplus::GdiplusShutdown(token);
});
...
}
my $0.02
struct at_scope_end
{
std::function < void () > Action;
at_scope_end (std::function < void () > Action) :
Action (Action)
{
}
~at_scope_end ()
{
Action ();
}
};
#define AT_SCOPE_END_CAT(x,y) x##y
#define AT_SCOPE_END_ID(index) AT_SCOPE_END_CAT(__sg, index)
#define AT_SCOPE_END(expr) at_scope_end AT_SCOPE_END_ID(__LINE__) ( [&] () { expr; } );
For the record, there is scope_exit in the TS 3
For the record, there is Boost ScopeExit.
We could omit the ugly [&] stuff by putting it in the define:
#define UTILITY_SCOPE_EXIT(f) const auto& _UTILITY_EXIT_SCOPE_LINENAME(EXIT, __LINE__) = ::detail::create_scope_exit([&]f)
Then:
UTILITY_SCOPE_EXIT({myfile.close();});
Tested with MSVC++ 11.0 (VS2012). Regards.