try catch finally construct - is it in C++11? [duplicate]
Asked Answered
U

3

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.

Ursala answered 15/10, 2011 at 18:9 Comment(4)
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.Xylophone
@David Heffernan, fortunately, with lambdas, using scope guards is easier than ever. :)Schist
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: https://mcmap.net/q/24807/-does-c-support-39-finally-39-blocks-and-what-39-s-this-39-raii-39-i-keep-hearing-aboutDefile
See my version of try-finally statement imitation too: https://mcmap.net/q/24807/-does-c-support-39-finally-39-blocks-and-what-39-s-this-39-raii-39-i-keep-hearing-aboutHypnos
C
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).

Cawnpore answered 15/10, 2011 at 18:20 Comment(4)
How do you guarantee that the destructor doesn't get called twice?Mucker
@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.Cawnpore
Does this get optimised as expected? e.g. does the check get removed?Mucker
@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<typename std::decay<decltype(functor)>::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.Cawnpore
X
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.

Xylophone answered 15/10, 2011 at 18:15 Comment(0)
C
8

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

Commendation answered 15/10, 2011 at 18:14 Comment(12)
but RAII is not always == finally.Ursala
@Ursala : It is if your destructors don't throw.Survey
@Survey && R.Marthinho not only, there are other cases where RAII != finallyUrsala
@Ursala : Care to mention an example? Because I can't think of one.. ;-]Survey
int main(){some_struct* p = new some_struct(1);some_struct* d = new some_struct(2); vector<int>* v = new vector<int>(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;}Ursala
@smallB: in which weird world is that horrible example not full of (memory-leak) bugs?Hardner
@Hardner It's just a snippet to show particular scenario, not a production codeUrsala
You can't really show the need for final by providing a complete insane snippet :p.Hardner
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 RAIIUrsala
@smallB: It can: scoped_ptr<some_struct> v = new some_struct; load_vector(v);. If load_vector throws, you won't leak memory in v. Done (+ code is even more readable).Impersonal
Downvote, an example is appreciated.Deadeye
@Deadeye +1. -1, I mean. It would be nice to provide a code snippet.Aggarwal

© 2022 - 2024 — McMap. All rights reserved.