Another "finally" block emulation using C++11 lambda functions
template <typename TCode, typename TFinallyCode>inline void with_finally(const TCode &code, const TFinallyCode &finally_code){ try { code(); } catch (...) { try { finally_code(); } catch (...) // Maybe stupid check that finally_code mustn't throw. { std::terminate(); } throw; } finally_code();}
Let's hope the compiler will optimize the code above.
Now we can write code like this:
with_finally( [&]() { try { // Doing some stuff that may throw an exception } catch (const exception1 &) { // Handling first class of exceptions } catch (const exception2 &) { // Handling another class of exceptions } // Some classes of exceptions can be still unhandled }, [&]() // finally { // This code will be executed in all three cases: // 1) exception was not thrown at all // 2) exception was handled by one of the "catch" blocks above // 3) exception was not handled by any of the "catch" block above });
If you wish you can wrap this idiom into "try - finally" macros:
// Please never throw exception below. It is needed to avoid a compilation error// in the case when we use "begin_try ... finally" without any "catch" block.class never_thrown_exception {};#define begin_try with_finally([&](){ try#define finally catch(never_thrown_exception){throw;} },[&]()#define end_try ) // sorry for "pascalish" style :(
Now "finally" block is available in C++11:
begin_try{ // A code that may throw}catch (const some_exception &){ // Handling some exceptions}finally{ // A code that is always executed}end_try; // Sorry again for this ugly thing
Personally I don't like the "macro" version of "finally" idiom and would prefer to use pure "with_finally" function even though a syntax is more bulky in that case.
You can test the code above here: http://coliru.stacked-crooked.com/a/1d88f64cb27b3813
PS
If you need a finally block in your code, then scoped guards or ON_FINALLY/ON_EXCEPTION macros will probably better fit your needs.
Here is short example of usage ON_FINALLY/ON_EXCEPTION:
void function(std::vector<const char*> &vector){ int *arr1 = (int*)malloc(800*sizeof(int)); if (!arr1) { throw "cannot malloc arr1"; } ON_FINALLY({ free(arr1); }); int *arr2 = (int*)malloc(900*sizeof(int)); if (!arr2) { throw "cannot malloc arr2"; } ON_FINALLY({ free(arr2); }); vector.push_back("good"); ON_EXCEPTION({ vector.pop_back(); }); ...