

C++11: Try/Catch/Finally Pattern Using RAII & Lambdas - code-dog
http://nerds-central.blogspot.com/2012/03/c11-trycatchfinally-pattern-using-raii.html

======
ot
What the OP describes here is a common C++ pattern known as "scope guard"
(check "Solution 4" in <http://drdobbs.com/184403758>). It was possible to
implement it in C++03 with some tricks but C++11 lambdas make it much easier.

This is a very nice small implementation but, as always with C++, devil is in
the details:

* Creation of an std::function needs a dynamic allocation, so if the allocation fails an exception will be thrown and if the _finally_ is guarding a resource, the resource will be leaked

* std::function has a non-negligible calling overhead, hence this should not be used in performance-sensitive code

* Checking a condition inside the finally clause is not very elegant, a better idiom in C++ is to support _dismissing_ a scope guard.

* The finallyClause may throw an exception, and since it is called in a destructor this is generally considered a bad idea. I don't know what could happen in this case, but some scope guard implementations I've seen catch the exception and explicitly call std::terminate(). I guess this is for performance reasons, because the destructor can be declared nothrow.

Here there is a more complex implementation, which addresses most of the
corner cases:

[http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-
Stepha...](http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-
Lavavej-Advanced-STL-6-of-n#c634477472460000000)

~~~
code-dog
I get your points. In general, the use cases for this pattern are not
production code. The post points out this is not a good way of handling
resource and that the example is about debugging. It would be up to the
implementer to ensure the finally clause does not throw and exception or to
catch it (I think there is something about nesting).

As for memory allocation failures, my experience is that depends a lot on the
platform. It is a common misconception that dynamic memory is likely to run
out and therefore we need to worry about that but not automatic memory.
However, I have seen stack overflow many many many more times than a genuine
'out of memory'. Further, if an application has actually run out of memory so
badly that a allocation of the closure's internal storage barfs then I suspect
it cannot be retrieved. Naturally this does not apply if your platform has a
very low heap size (e.g. realtime hardware or some such).

------
evincarofautumn
I’ve done this before, and this version has a significant flaw: it is not
exception-safe. The destructor should not read as it does:

    
    
        ~finally() {
            finallyClause();
        }
    

This allows exceptions thrown by finallyClause() to propagate out of the
destructor, which, if an exception is already being thrown, will result in a
call to std::terminate(), causing the application to die horrifically. Because
C++ kinda-should’ve-but-really-doesn’t have checked exceptions, we must simply
discard them:

    
    
        ~finally() {
            try { finallyClause(); } catch (...) {}
        }
    

You can also avoid problems with exceptions and std::function’s dynamic
allocation by using a template instead:

    
    
        template<class F>
        class finally_type {
        public:
    
            explicit finally_type(F f) : function(f) {}
            ~finally_type() { try { function(); } catch (...) {} }
    
        private:
    
            finally_type(const finally_type&);
            finally_type& operator=(const finally_type&);
            F function;
    
        };
    
        template<class F>
        finally_type<F> finally(F f) { return finally_type<F>(f); }
    

This can be used like so:

    
    
        void test() {
            int* i = new int;
            auto cleanup = finally([i]() { delete i; });
            may_throw();
        }
    
    

Finally (har!) the equivalent idiom in C++03:

    
    
        void test() {
    
            int* i = new int;
    
            struct finally {
                finally(int* i) : i(i) {}
                ~finally() { delete i; }
                int* i;
            } cleanup(i);
    
            may_throw();
    
        }

~~~
ot
> Because C++ kinda-should’ve-but-really-doesn’t have checked exceptions, we
> must simply discard them:

This would make the error pass silently, possibly leaving the program in an
inconsistent state. It is probably better to call std::terminate() instead,
which is what C++ does when an exception is thrown when another exception is
active.

~~~
evincarofautumn
You’re quite right that ignoring the (programmer) error is too lax, but
std::terminate() is far too extreme. This is perhaps a situation for
std::nested_exception:

    
    
        ~finally_type() {
            try {
                function();
            } catch (...) {
                std::throw_with_nested(std::logic_error
                    ("Exception thrown from \"finally\"."));
            }
        }
    

It might pollute calling code a bit with calls to std::rethrow_if_nested(),
but I think it’s worth it for the safety.

~~~
ot
No, if the finally clause is called while an exception is active, the runtime
will call std::terminate(). This is why it is bad practice to throw exceptions
in destructors.

Hence, in most cases where the scope guard pattern is used (to guarantee
exception safety), your code is basically equivalent to calling
std::terminate().

~~~
evincarofautumn
Alright, yeah, no exception should escape the finally destructor. After so
many years of using it, I should know better than to write C++.

But anyway, the problem is still _programmer_ error. Just as you shouldn’t
throw an exception from a destructor, you shouldn’t throw an exception from a
“finally”, because it is, by definition, run in a destructor. So, sure,
calling std::terminate() explicitly makes about as much sense as anything, but
I’d prefer to ignore (and perhaps log) such erroneous exceptions, for reasons
of stability.

------
NerdsCentral
I was not expecting this to produce so much interest. I guess a lot of people
have asked about how to implement try/catch/finally in C++.

