Published: Mo 11 April 2016 In 2016. tags: programming C++

Recently the developer of LibrePCB asked me about a C++ pattern to undo parts of an action if an exception gets thrown in the middle of it.

Of course he basically described the main usage of a ScopeGuard. I went ahead and implemented one based on a talk by Andrei Alexandrescu.

Basic use of a ScopeGuard The ScopeGuard allows to write transactional code that will undo previous parts if later code throws an exception. myVector . push_back ( item ); auto guard = scopeGuard ([ & ]() { myVector . pop_back () }); // Do stuff that may throw database . add ( item ); // everything worked, so don't undo guard . dismiss (); So if database.add(item) throws, the item in myVector will be removed. For more about the motivation behind ScopeGuard see the talk above or this drdobbs article. Using C++11 and later the implementation is fairly simple: struct ScopeGuardBase { ScopeGuardBase () : mActive ( true ) { } ScopeGuardBase ( ScopeGuardBase && rhs ) : mActive ( rhs . mActive ) { rhs . dismiss (); } void dismiss () noexcept { mActive = false ; } protected : ~ ScopeGuardBase () = default ; bool mActive ; }; template < class Fun > struct ScopeGuard : public ScopeGuardBase { ScopeGuard () = delete ; ScopeGuard ( const ScopeGuard & ) = delete ; ScopeGuard ( Fun f ) noexcept : ScopeGuardBase (), mF ( std :: move ( f )) { } ScopeGuard ( ScopeGuard && rhs ) noexcept : ScopeGuardBase ( std :: move ( rhs )), mF ( std :: move ( rhs . mF )) { } ~ ScopeGuard () noexcept { if ( mActive ) { try { mF (); } catch (...) {} } } ScopeGuard & operator = ( const ScopeGuard & ) = delete ; private : Fun mF ; }; template < class Fun > ScopeGuard < Fun > scopeGuard ( Fun f ) { return ScopeGuard < Fun > ( std :: move ( f )); }

Why a ScopeGuardList? If you have a transaction that consists of a lot of steps that may throw and need to be undone it leads to code like the following: doThing1 (); auto guard = makeGuard ([ & ]() { undoThing1 (); }); doThing2 (); auto guard = makeGuard ([ & ]() { undoThing2 (); }); doThing3 (); auto guard = makeGuard ([ & ]() { undoThing3 (); }); // Do stuff that may trow guard1 . dismiss (); guard2 . dismiss (); guard3 . dismiss (); Things get even worse when doing something in a loop: for ( int i = 0 ; i < 10 ; ++ i ) { doStuff ( i ); // how do we create a guard for every operation? } To avoid that repetition and the potential error of a missing call to dismiss() we came up with a ScopeGuardList .