Quantcast
Channel: Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?) - Stack Overflow
Viewing all articles
Browse latest Browse all 17

Answer by Fabio A. for Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?)

$
0
0

I came up with a finally macro that can be used almost like¹ the finally keyword in Java; it makes use of std::exception_ptr and friends, lambda functions and std::promise, so it requires C++11 or above; it also makes use of the compound statement expression GCC extension, which is also supported by clang.

WARNING: an earlier version of this answer used a different implementation of the concept with many more limitations.

First, let's define a helper class.

#include <future>template <typename Fun>class FinallyHelper {    template <typename T> struct TypeWrapper {};    using Return = typename std::result_of<Fun()>::type;public:        FinallyHelper(Fun body) {        try {            execute(TypeWrapper<Return>(), body);        }        catch(...) {            m_promise.set_exception(std::current_exception());        }    }    Return get() {        return m_promise.get_future().get();    }private:    template <typename T>    void execute(T, Fun body) {        m_promise.set_value(body());    }    void execute(TypeWrapper<void>, Fun body) {        body();    }    std::promise<Return> m_promise;};template <typename Fun>FinallyHelper<Fun> make_finally_helper(Fun body) {    return FinallyHelper<Fun>(body);}

Then there's the actual macro.

#define try_with_finally for(auto __finally_helper = make_finally_helper([&] { try #define finally });                         \        true;                               \        ({return __finally_helper.get();})) \/***/

It can be used like this:

void test() {    try_with_finally {        raise_exception();    }        catch(const my_exception1&) {        /*...*/    }    catch(const my_exception2&) {        /*...*/    }    finally {        clean_it_all_up();    }    }

The use of std::promise makes it very easy to implement, but it probably also introduces quite a bit of unneeded overhead which could be avoided by reimplementing only the needed functionalities from std::promise.


¹CAVEAT: there are a few things that don't work quite like the java version of finally. Off the top of my head:

  1. it's not possible to break from an outer loop with the break statement from within the try and catch()'s blocks, since they live within a lambda function;
  2. there must be at least one catch() block after the try: it's a C++ requirement;
  3. if the function has a return value other than void but there's no return within the try and catch()'s blocks, compilation will fail because the finally macro will expand to code that will want to return a void. This could be, err, avoided by having a finally_noreturn macro of sorts.

All in all, I don't know if I'd ever use this stuff myself, but it was fun playing with it. :)


Viewing all articles
Browse latest Browse all 17

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>