5

Possible Duplicate:
Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?)

Does try/catch/finally construct is supported in C++11?
I'm asking because I couldn't find anywhere information about it. Thanks.

Community
  • 1
  • 1
smallB
  • 16,662
  • 33
  • 107
  • 151
  • 1
    For what it's worth, the problem with RAII, in my view, is that it strongly constrains your class hierarchy design. There are situations where you want tidy up but you don't naturally have a class available to force that tidy up. – David Heffernan Oct 15 '11 at 18:24
  • 1
    @David Heffernan, fortunately, with lambdas, using scope guards is easier than ever. :) – avakar Oct 15 '11 at 18:51
  • As others have said, C++11 does not directly support the finally keyword. However, it's possible to implement and use it seamlessy. See my answer here: http://stackoverflow.com/a/38701485/566849 – Fabio A. Aug 01 '16 at 14:44
  • See my version of try-finally statement imitation too: https://stackoverflow.com/a/47574378/5447906 – anton_rh Nov 30 '17 at 13:25

3 Answers3

18

Not an excuse to forgo RAII, but useful when e.g. using non RAII aware APIs:

template<typename Functor>
struct finally_guard {
    finally_guard(Functor f)
        : functor(std::move(f))
        , active(true)
    {}

    finally_guard(finally_guard&& other)
        : functor(std::move(other.functor))
        , active(other.active)
    { other.active = false; }

    finally_guard& operator=(finally_guard&&) = delete;

    ~finally_guard()
    {
        if(active)
            functor();
    }

    Functor functor;
    bool active;
};

template<typename F>
finally_guard<typename std::decay<F>::type>
finally(F&& f)
{
    return { std::forward<F>(f) };
}

Usage:

auto resource = /* acquire */;
auto guard = finally([&resource] { /* cleanup */ });
// using just
// finally([&resource] { /* cleanup */ });
// is wrong, as usual

Note how you don't need a try block if you don't need to translate or otherwise handle exceptions.

While my example makes use of C++11 features, the same generic functionality was available with C++03 (no lambdas though).

Luc Danton
  • 34,649
  • 6
  • 70
  • 114
  • 2
    How do you guarantee that the destructor doesn't get called twice? – ioquatix Feb 15 '12 at 12:32
  • @MrSamuel Good catch. This does need a flag to check the current status of *this (e.g. a moved-from object will get deactivated). I did fix it in my actual code, I'm updating this answer. – Luc Danton Feb 15 '12 at 13:41
  • Does this get optimised as expected? e.g. does the check get removed? – ioquatix Feb 15 '12 at 23:08
  • @MrSamuel There's no way of telling in advance. The only way to avoid that flag entirely is to use binding to temporaries: `finally_guard::type>&& guard = { std::move(functor) };`. This is exactly one construction. It can't be refactored into a function (getting a value across a function either means constructing, or returning a dangling reference with no lifetime extension), but can be refactored into a macro. However, this wouldn't work with a lambda expressions due to `decltype`. So you can't win them all. – Luc Danton Feb 15 '12 at 23:37
13

C++11 does not add support for finally. The decision makers (especially Stroustrup) have for many many years expressed a preference for other idioms, i.e. RAII. I think it is exceptionally unlikely that C++ will ever include finally.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
8

You don't need finally in C++ because C++ has RAII which is much nicer.

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • 3
    but RAII is not always == finally. – smallB Oct 15 '11 at 18:36
  • @smallB : It is if your destructors don't throw. – ildjarn Oct 15 '11 at 20:37
  • @ildjarn && R.Marthinho not only, there are other cases where RAII != finally – smallB Oct 16 '11 at 17:11
  • @smallB : Care to mention an example? Because I can't think of one.. ;-] – ildjarn Oct 16 '11 at 17:31
  • int main(){some_struct* p = new some_struct(1);some_struct* d = new some_struct(2); vector* v = new vector(5);try{load_vector(v);}catch(const vector_overflow& e){delete v;//if this for some reason will not succed:}finally{delete d;delete p;//but only if destruction of v wasn't successfull} return 0;} – smallB Oct 17 '11 at 06:00
  • @smallB: in which weird world is that horrible example not full of (memory-leak) bugs? – KillianDS Oct 17 '11 at 11:34
  • @KillianDS It's just a snippet to show particular scenario, not a production code – smallB Oct 17 '11 at 12:13
  • 5
    You can't really show the need for final by providing a complete insane snippet :p. – KillianDS Oct 17 '11 at 12:23
  • 5
    I don't think it is insane. It clearly shows that there are a situations that depending on error require different approach and finally is a clean way to do it. And It cannot be done as cleanly with RAII – smallB Oct 17 '11 at 16:23
  • 1
    @smallB: It can: `scoped_ptr v = new some_struct; load_vector(v);`. If `load_vector` throws, you won't leak memory in `v`. Done (+ code is even more readable). – Sebastian Mach Nov 07 '11 at 16:38
  • 1
    Downvote, an example is appreciated. – To1ne Sep 05 '12 at 10:26
  • @To1ne +1. -1, I mean. It would be nice to provide a code snippet. – Spook Apr 16 '14 at 07:22