title: The simplest and neatest c++11 ScopeGuard
body: <p>I'm attempting to write a simple <a href="http://www.drdobbs.com/cpp/184403758" rel="noreferrer">ScopeGuard based on Alexandrescu concepts</a> but with c++11 idioms. </p>
  
  <pre><code>namespace RAII
  {
      template&lt; typename Lambda &gt;
      class ScopeGuard
      {
          mutable bool committed;
          Lambda rollbackLambda; 
          public:
  
              ScopeGuard( const Lambda&amp; _l) : committed(false) , rollbackLambda(_l) {}
  
              template&lt; typename AdquireLambda &gt;
              ScopeGuard( const AdquireLambda&amp; _al , const Lambda&amp; _l) : committed(false) , rollbackLambda(_l)
              {
                  _al();
              }
  
              ~ScopeGuard()
              {
                  if (!committed)
                      rollbackLambda();
              }
              inline void commit() const { committed = true; }
      };
  
      template&lt; typename aLambda , typename rLambda&gt;
      const ScopeGuard&lt; rLambda &gt;&amp; makeScopeGuard( const aLambda&amp; _a , const rLambda&amp; _r)
      {
          return ScopeGuard&lt; rLambda &gt;( _a , _r );
      }
  
      template&lt;typename rLambda&gt;
      const ScopeGuard&lt; rLambda &gt;&amp; makeScopeGuard(const rLambda&amp; _r)
      {
          return ScopeGuard&lt; rLambda &gt;(_r );
      }
  }
  </code></pre>
  
  <p>Here is the usage:</p>
  
  <pre><code>void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptions() 
  {
     std::vector&lt;int&gt; myVec;
     std::vector&lt;int&gt; someOtherVec;
  
     myVec.push_back(5);
     //first constructor, adquire happens elsewhere
     const auto&amp; a = RAII::makeScopeGuard( [&amp;]() { myVec.pop_back(); } );  
  
     //sintactically neater, since everything happens in a single line
     const auto&amp; b = RAII::makeScopeGuard( [&amp;]() { someOtherVec.push_back(42); }
                       , [&amp;]() { someOtherVec.pop_back(); } ); 
  
     b.commit();
     a.commit();
  }
  </code></pre>
  
  <p>Since my version is way shorter than most examples out there (like Boost ScopeExit) i'm wondering what specialties i'm leaving out. Hopefully i'm in a 80/20 scenario here (where i got 80 percent of neatness with 20 percent of lines of code), but i couldn't help but wonder if i'm missing something important, or is there some shortcoming worth mentioning of this version of the ScopeGuard idiom</p>
  
  <p>thanks!</p>
  
  <p><strong>Edit</strong> I noticed a very important issue with the makeScopeGuard that takes the adquire lambda in the constructor. If the adquire lambda throws, then the release lambda is never called, because the scope guard was never fully constructed. In many cases, this is the desired behavior, but i feel that sometimes a version that will invoke rollback if a throw happens is desired as well:</p>
  
  <pre><code>//WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
  template&lt; typename aLambda , typename rLambda&gt;
  ScopeGuard&lt; rLambda &gt; // return by value is the preferred C++11 way.
  makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
  {
      return ScopeGuard&lt; rLambda &gt;( std::forward&lt;aLambda&gt;(_a) , std::forward&lt;rLambda&gt;(_r )); // *** no longer UB, because we're returning by value
  }
  
  template&lt; typename aLambda , typename rLambda&gt;
  ScopeGuard&lt; rLambda &gt; // return by value is the preferred C++11 way.
  makeScopeGuardThatDoesRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
  {
      auto scope = ScopeGuard&lt; rLambda &gt;(std::forward&lt;rLambda&gt;(_r )); // *** no longer UB, because we're returning by value
      _a();
      return scope;
  }
  </code></pre>
  
  <hr>
  
  <p>so for completeness, i want to put in here the complete code, including tests:</p>
  
  <hr>
  
  <pre><code>#include &lt;vector&gt;
  
  namespace RAII
  {
  
      template&lt; typename Lambda &gt;
      class ScopeGuard
      {
          bool committed;
          Lambda rollbackLambda; 
          public:
  
              ScopeGuard( const Lambda&amp; _l) : committed(false) , rollbackLambda(_l) {}
  
              ScopeGuard( const ScopeGuard&amp; _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda) 
              {
                  if (_sc.committed)
                     committed = true;
                  else
                     _sc.commit();
              }
  
              ScopeGuard( ScopeGuard&amp;&amp; _sc) : committed(false) , rollbackLambda(_sc.rollbackLambda)
              {
                  if (_sc.committed)
                     committed = true;
                  else
                     _sc.commit();
              }
  
              //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
              template&lt; typename AdquireLambda &gt;
              ScopeGuard( const AdquireLambda&amp; _al , const Lambda&amp; _l) : committed(false) , rollbackLambda(_l)
              {
                 std::forward&lt;AdquireLambda&gt;(_al)();
              }
  
              //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
              template&lt; typename AdquireLambda, typename L &gt;
              ScopeGuard( AdquireLambda&amp;&amp; _al , L&amp;&amp; _l) : committed(false) , rollbackLambda(std::forward&lt;L&gt;(_l))
              {
                  std::forward&lt;AdquireLambda&gt;(_al)(); // just in case the functor has &amp;&amp;-qualified operator()
              }
  
  
              ~ScopeGuard()
              {
                  if (!committed)
                      rollbackLambda();
              }
              inline void commit() { committed = true; }
      };
  
  
      //WARNING: only safe if adquire lambda does not throw, otherwise release lambda is never invoked, because the scope guard never finished initialistion..
      template&lt; typename aLambda , typename rLambda&gt;
      ScopeGuard&lt; rLambda &gt; // return by value is the preferred C++11 way.
      makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
      {
          return ScopeGuard&lt; rLambda &gt;( std::forward&lt;aLambda&gt;(_a) , std::forward&lt;rLambda&gt;(_r )); // *** no longer UB, because we're returning by value
      }
  
      template&lt; typename aLambda , typename rLambda&gt;
      ScopeGuard&lt; rLambda &gt; // return by value is the preferred C++11 way.
      makeScopeGuardThatDoesRollbackIfAdquireThrows( aLambda&amp;&amp; _a , rLambda&amp;&amp; _r) // again perfect forwarding
      {
          auto scope = ScopeGuard&lt; rLambda &gt;(std::forward&lt;rLambda&gt;(_r )); // *** no longer UB, because we're returning by value
          _a();
          return scope;
      }
  
      template&lt;typename rLambda&gt;
      ScopeGuard&lt; rLambda &gt; makeScopeGuard(rLambda&amp;&amp; _r)
      {
          return ScopeGuard&lt; rLambda &gt;( std::forward&lt;rLambda&gt;(_r ));
      }
  
      namespace basic_usage
      {
          struct Test
          {
  
              std::vector&lt;int&gt; myVec;
              std::vector&lt;int&gt; someOtherVec;
              bool shouldThrow;
              void run()
              {
                  shouldThrow = true;
                  try
                  {
                      SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
                  } catch (...)
                  {
                      AssertMsg( myVec.size() == 0 &amp;&amp; someOtherVec.size() == 0 , "rollback did not work");
                  }
                  shouldThrow = false;
                  SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows();
                  AssertMsg( myVec.size() == 1 &amp;&amp; someOtherVec.size() == 1 , "unexpected end state");
                  shouldThrow = true;
                  myVec.clear(); someOtherVec.clear();  
                  try
                  {
                      SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesRollbackIfAdquireThrows();
                  } catch (...)
                  {
                      AssertMsg( myVec.size() == 0 &amp;&amp; someOtherVec.size() == 0 , "rollback did not work");
                  }
              }
  
              void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesNOTRollbackIfAdquireThrows() //throw()
              {
  
                  myVec.push_back(42);
                  auto a = RAII::makeScopeGuard( [&amp;]() { HAssertMsg( myVec.size() &gt; 0 , "attempt to call pop_back() in empty myVec"); myVec.pop_back(); } );  
  
                  auto b = RAII::makeScopeGuardThatDoesNOTRollbackIfAdquireThrows( [&amp;]() { someOtherVec.push_back(42); }
                                      , [&amp;]() { HAssertMsg( myVec.size() &gt; 0 , "attempt to call pop_back() in empty someOtherVec"); someOtherVec.pop_back(); } );
  
                  if (shouldThrow) throw 1; 
  
                  b.commit();
                  a.commit();
              }
  
              void SomeFuncThatShouldBehaveAtomicallyInCaseOfExceptionsUsingScopeGuardsThatDoesRollbackIfAdquireThrows() //throw()
              {
                  myVec.push_back(42);
                  auto a = RAII::makeScopeGuard( [&amp;]() { HAssertMsg( myVec.size() &gt; 0 , "attempt to call pop_back() in empty myVec"); myVec.pop_back(); } );  
  
                  auto b = RAII::makeScopeGuardThatDoesRollbackIfAdquireThrows( [&amp;]() { someOtherVec.push_back(42); if (shouldThrow) throw 1; }
                                      , [&amp;]() { HAssertMsg( myVec.size() &gt; 0 , "attempt to call pop_back() in empty someOtherVec"); someOtherVec.pop_back(); } );
  
                  b.commit();
                  a.commit();
              }
          };
      }
  }
  </code></pre>