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:
- it's not possible to break from an outer loop with the
breakstatement from within thetryandcatch()'s blocks, since they live within a lambda function; - there must be at least one
catch()block after thetry: it's a C++ requirement; - if the function has a return value other than void but there's no return within the
tryandcatch()'sblocks, compilation will fail because thefinallymacro will expand to code that will want to return avoid. This could be, err, avoided by having afinally_noreturnmacro of sorts.
All in all, I don't know if I'd ever use this stuff myself, but it was fun playing with it. :)