Does C++ support 'finally' blocks? (And what's this 'RAII' I keep hearing about?)
Asked Answered
T

16

340

Does C++ support 'finally' blocks?

What is the RAII idiom?

What is the difference between C++'s RAII idiom and C#'s 'using' statement?

Terce answered 2/10, 2008 at 7:14 Comment(1)
Also see the answers in: #7780152Woodwork
T
327

No, C++ does not support 'finally' blocks. The reason is that C++ instead supports RAII: "Resource Acquisition Is Initialization" -- a poor name for a really useful concept.

The idea is that an object's destructor is responsible for freeing resources. When the object has automatic storage duration, the object's destructor will be called when the block in which it was created exits -- even when that block is exited in the presence of an exception. Here is Bjarne Stroustrup's explanation of the topic.

A common use for RAII is locking a mutex:

// A class with implements RAII
class lock
{
    mutex &m_;

public:
    lock(mutex &m)
      : m_(m)
    {
        m.acquire();
    }
    ~lock()
    {
        m_.release();
    }
};

// A class which uses 'mutex' and 'lock' objects
class foo
{
    mutex mutex_; // mutex for locking 'foo' object
public:
    void bar()
    {
        lock scopeLock(mutex_); // lock object.

        foobar(); // an operation which may throw an exception

        // scopeLock will be destructed even if an exception
        // occurs, which will release the mutex and allow
        // other functions to lock the object and run.
    }
};

RAII also simplifies using objects as members of other classes. When the owning class' is destructed, the resource managed by the RAII class gets released because the destructor for the RAII-managed class gets called as a result. This means that when you use RAII for all members in a class that manage resources, you can get away with using a very simple, maybe even the default, destructor for the owner class since it doesn't need to manually manage its member resource lifetimes. (Thanks to Mike B for pointing this out.)

For those familliar with C# or VB.NET, you may recognize that RAII is similar to .NET deterministic destruction using IDisposable and 'using' statements. Indeed, the two methods are very similar. The main difference is that RAII will deterministically release any type of resource -- including memory. When implementing IDisposable in .NET (even the .NET language C++/CLI), resources will be deterministically released except for memory. In .NET, memory is not deterministically released; memory is only released during garbage collection cycles.

 

† Some people believe that "Destruction is Resource Relinquishment" is a more accurate name for the RAII idiom.

Terce answered 2/10, 2008 at 7:14 Comment(26)
RAII is stuck -- there's really no changing it. Trying to do so would be foolish. However, you have to admit though that "Resource Acquisition Is Initialization" is still a pretty poor name.Terce
SBRM == Scope Bound Resource ManagementDonkey
@Kevin: During usage, RAII is really not similar to using: You can't span a using-statement over your class' initializer/finalizer. You have to be explicit and not forget the using-statement. Nesting gets horrible. The usecases for using vs. RAII are basically nought: scoped locks, vectors, strings, shared pointers, transactions, and all those without the need to manually write using(). In the way you present it, using is a poor defense before RAII, and I realise many .net-devs try hard to convince themselves that RAII is similar, but in their heart they (should) know it is not.Everybody
This leaves you stuck when you have something to clean up that doesn't match any C++ object's lifetime. I guess you end up with Lifetime Equals C++ Class Liftime Or Else It Gets Ugly (LECCLEOEIGU?).Tern
I'm thinking something similar to Warren: wait, what happens when you have code that should Definitely Execute, but not at the end of an object lifetime? Isn't there still a use case for "finally", and the absence of that in C++ is therefore a hole in design space? In addition, relying on Destructor means that C++ is forced to always be implemented using DETERMINISTIC memory lifetimes. No future version of C++ could use Garbage Collection instead, because everyone is relying on timely execution of destructors.Jeepers
@WarrenP Then you should wrap that "something" into a class. That's the entire core of RAII, and in fact it will often force you into a better design.Diatomic
@ToolMakerSteve The same goes for you, wrap it. It's also not a hole in design, since if you wanted to do gc in C++, you'd probably do it on raw pointers (or maybe on a specific pointer class, but then there's even less relevance), and delete always comes before a gc can kick in. In other words, it'll only influence broken(/leaking) current code where you already couldn't rely on constructors.Diatomic
@Jasper: And that's why there are so many almost entirely useless classes in every codebase. Because C++ gives you no other choice. That's called a language wart.Tern
@WarrenP No, that's called the single responsibility principle.Diatomic
I always like to thing of the single responsibility of a class as having more bandwidth inside it than "paper over this language's limitations".Tern
Well, personally, I prefer it when a language decides not to do magic and instead gives you the powerful tools to do things yourself, and telling the only way to do it is in a maintainable and scalable way that solves the problem internally to the code isn't a problem to me, honestly. Look at the alternatives, Java puts it in the hands of the calling code with finally, C# gives the same method and some magic through using, scripting languages often give you similar solutions but also say that limited execution time should prevent big issues. I'd take RAII any day.Diatomic
@Jasper: Wrapping into a class is obviously sensible when (the state to be managed) is part of what a service does. However, It seems cumbersome when it is a one-off need (of the client or GUI code) as part of responding to a specific user action. For example, at one point in my client logic, I need to remember the current value of several (fields of a rendering engine - I can't change its source code), set them to needed values, and then restore them when done. To create a class for that single usage in a single routine is overkill. "Finally" would be a concise and safe solution.Jeepers
@Jasper: I deleted one of my comments -- decided adding non-deterministic GC to C++ would make an already too-complex language even more head-spinning. The real issue is that the years I programmed in C++, before Java or .Net existed, I found it unpleasant - and still do, when I need to use it. I'd love to see a re-invention of C++, starting from scratch, that was as clean as python or C#, with a class library based on RAII, smart pointers, and/or weak references: deterministic GC solutions. Yes, all that exists in C++, but a cleaner language to think in. Admittedly off-topic...Jeepers
@Jeepers Deleted one of my response to it before that :P, when I realized the mistake I was making. Anyway, I agree that a clean non-managed language would be great (or, perhaps there might even be a good way to mix managed and unmanaged). Even Bjarne Soustroup basically said as much (he would now rather not have the baggage of C-compatibility, but he can't change that now). I've found needing to think about ownership a good thing. Of course, you should almost always use C++ things over C-things, which doesn't always happen and wasn't always possible back when Java and didn't exist yet.Diatomic
Personally I don't feel that this RAll is really good alternative for a finally block. It just means that, for proper cleanup, you have to wrap resources into artificial objects just to get the automatic cleanuo, as Warren P pointed ou tin his comment above (Language wart).Lamoureux
@Lamoureux You can create a very simple template object to do such thing for whatever two methods you need to call on initialization and deinitialization. To be honest, I wouldn't be surprised if such template class was already in the STL. (But it is most likely not there (yet?))Eulalie
Yes, because this is so much less code than <snark> mutex_.lock(); try{ foobar(); }finally{ mutex_,unlock(); } </snark> wrapper objects, templates, boy this c++11 sure is much simpler!Accumulative
@TonyBenBrahim Multiplied throughout your entire code base, applying to all resources for which you need deterministic cleanup? Yes. Yes it is.Rockel
@Cubic, yes I realize that now. Takes some getting used to though, coming from Java.Accumulative
@Diatomic I can think of a situation (probably uncommon, but I don't know) where it would probably be cleaner to at least have try...finally available, provided it wasn't needed in multiple locations: Working directly with hardware. Suppose that a specific memory location should normally have an "all clear" flag, but the flag should be changed during certain operations. If these operations are handled by a single function, it would be cleaner to have try { uintX_t* flag = some_address; *flag = WHATEVER; /* ... */ } finally { *flag = ALL_CLEAR; },Lugger
than it would to have to write a class to wrap a non-owning pointer that's only used by that one function: In this case, the class would just add a level of indirection, and make it less clear to the programmer what's going on. Now, if the flag needed to be checked in multiple locations, it would be a different story, but this particular design would be a bit cleaner without battering RAII into an awkward kludge.Lugger
Generally speaking, though, RAII is definitely the cleaner alternative, IMO. I just find it strange that the language doesn't have both, even though sometimes a simple one-off may be cleaner than a class that's only used in one particular location for one particular task.Lugger
Then again, I'm the type of person that prefers to have exactly the right tool for a given job instead of improvising with another one, if possible, so that likely influences my belief that both options should be available instead of just one or the other.Lugger
@Jan It's not in the C++ standard library, but there's BOOST_SCOPE_EXIT if you can forgive the syntactic boilerplate, and that the body of your code mustn't throw. boost.org/doc/libs/1_65_1/libs/scope_exit/doc/html/scope_exit/…Baleful
@WarrenP I included your suggested acronym, along with others, in this answer: https://mcmap.net/q/24811/-pattern-name-for-create-in-constructor-delete-in-destructor-cFagaly
The very short version is: finally support is not needed because C++ supports destructors. Destructors can be coerced into doing anything a finally block could do.Cartogram
B
83

In C++ the finally is NOT required because of RAII.

RAII moves the responsibility of exception safety from the user of the object to the designer (and implementer) of the object. I would argue this is the correct place as you then only need to get exception safety correct once (in the design/implementation). By using finally you need to get exception safety correct every time you use an object.

Also IMO the code looks neater (see below).

Example:

A database object. To make sure the DB connection is used it must be opened and closed. By using RAII this can be done in the constructor/destructor.

C++ Like RAII

void someFunc()
{
    DB    db("DBDesciptionString");
    // Use the db object.

} // db goes out of scope and destructor closes the connection.
  // This happens even in the presence of exceptions.

The use of RAII makes using a DB object correctly very easy. The DB object will correctly close itself by the use of a destructor no matter how we try and abuse it.

Java Like Finally

void someFunc()
{
    DB      db = new DB("DBDesciptionString");
    try
    {
        // Use the db object.
    }
    finally
    {
        // Can not rely on finaliser.
        // So we must explicitly close the connection.
        try
        {
            db.close();
        }
        catch(Throwable e)
        {
           /* Ignore */
           // Make sure not to throw exception if one is already propagating.
        }
    }
}

When using finally the correct use of the object is delegated to the user of the object. i.e. It is the responsibility of the object user to correctly to explicitly close the DB connection. Now you could argue that this can be done in the finaliser, but resources may have limited availability or other constraints and thus you generally do want to control the release of the object and not rely on the non deterministic behavior of the garbage collector.

Also this is a simple example.
When you have multiple resources that need to be released the code can get complicated.

A more detailed analysis can be found here: http://accu.org/index.php/journals/236

Bleach answered 2/10, 2008 at 7:47 Comment(23)
// Make sure not to throw exception if one is already propagating. It is important for C++ destructors not to throw exceptions as well for this very reason.Basque
@Cemafor: The reason for C++ not to throw exceptions out of the destructor is different than Java. In Java it will work (you just loose the original exception). In C++ its really bad. But the point in C++ is that you only have to do it once (by the designer of the class) when he writes the destructor. In Java you have to do it at the point of usage. So it is the responsibility of the user of the class to write the same boiler plate very time.Bleach
If it's a matter of being "needed", you don't need RAII either. Let's get rid of it! :-) Jokes aside, RAII is fine for a lot cases. What RAII does makes more cumbersome is cases when you want to execute some code (not resource related) even if the code above returned early. For that either you use gotos or separate it into two methods.Superb
@Trinidad: You are going to have to be a lot more specific than that. You should start a question about situations where RAII is more cumbersome and get some real feedback on the ways that you should be doing it.Bleach
@LokiAstari Oh it's pretty simple, imagine for example I'm building a datastructure from an XML file and I want to print it out in the end of the function. The thing is my code has a bunch of returns in the loading part, so I don't have to do a lot of ifs down the road. RAII would be very cumbersome, as it would require me to create a class just to do the pretty-print, ridiculous. Either you use gotos instead of the returns, or separate the loading from the printing as different functions. I agree this perhaps it's not the best example, but it's ludicrous to think RAII=finallySuperb
@Trinidad: Its not a simple as you think (as all your suggestions seem to pick the worst options possible). Which is why a question may be a better place to explore this than the comments.Bleach
java 7+ finally: try ( DB db = new DB("DBDesciptionString")){ //use db}Accumulative
@TonyBenBrahim: At least Java is moving towards C++ in small steps. But that is the adoption of C# use directive. A step but not as powerfull as RAII ;-)Bleach
Although I think your answer is very good, I would argue against the "because of RAII". I think it would be better to say: "no, but you can avoid it miss by using RAII".Gaultheria
So, if C++ destructors can't throw exceptions and don't have return values, how the hell are you supposed to report errors from them? Like if a database connection destructor needs to commit or rollback an unfinished transaction, or if a file stream destructor needs to flush a buffer, and this operation fails for whatever reason. You could solve this issue by introducing an explicit cleanup function (close/dispose/disconnect/etc.) that returns an error code, but basically this makes C++'s implicit destructor calls useless.Driver
@dan04: C++ destructors CAN throw exceptions. Its just not a goo idea usually. They just can't throw an exception when an exception is already propagating. See: #130617 and codereview.stackexchange.com/questions/540/… (read the last comment on this one).Bleach
@Driver There's another idiom for these cases. It's called a scope guard. The scope guard takes a lambda/function pointer/whatever-you-want on construction and executes it upon destruction. This allows you to define a section of code that effectively runs like a finally block, except the cleanup code can be easily disabled, changed to different scopes or injected into other places. I don't recommend using exceptions in any implicitly called code (IE destructors) at all, as it may cause exceptions to occur at unintended times.Hemitrope
Criticizing the "is NOT required because of RAII": there are plenty of cases where adding ad-hoc RAII would be too much boilerplate code to add, and try-finally would just be extremely appropriate.Temporize
@Temporize I would argue that try/finally uses much more bolierplate. The trouble is that try/finally needs to be done each time it is used (see example above). While RAII only has to be done once by the original author. The other problem with try/finally is you are shifting the burden of correct usage from the author to the user. Getting the user to do it correctly every time is much harder than getting the author to do it correctly once.Bleach
@MartinYork I'm not saying try-finally should be always used instead of RAII. You are right that APIs should provide appropriate destructors for their structs, or provide RAII guards where appropriate (example for handling transactions). What I'm saying is that there are some circumstances in final user code where adding RAII is not the most sound instrument he may want to use, and try-finally would do the job without creating boring ad-hoc structs for RAII. In short: both would be good to have and the wise programmer would use the most appropriate in each situation.Temporize
@MartinYork Sometimes the "user vs author" distinction just doesn't apply. Say at the end of my main() I want to write out a file that says ERROR or OK depending on what happened. I would do something like bool ok = false; try { /* do stuff */; ok = true; } catch (...) { ... } finally { write_my_file(ok); }. Now I have to write a class for that and I become the "author" of a class I wouldn't have needed if I were able to fix it being a "user".Franks
@Franks True. But in your way, then every-time you want to use this pattern you have to manually add all the above boiler-plate (and remember to do it correctly and test it works correctly). In my way you do it once in a class. Now you can test it once (it will forever after be correct once tested) and you can re-use the pattern simply be declaring an object in the correct scope. So if you only ever do it once then sure the finally may work out simpler. But how often do you do something once in your lifetime? There are also libraries that simply execute a lambda on destruction.Bleach
@Franks bool ok = false; gsl::final_act finalAction([&ok](){write_my_file(ok);}); /* do stuff */; ok = true; Seems a lot less bolier-platey to me.Bleach
@MartinYork, At first sight, your piece of code is about as long as mine (and you left out the try/catch block which would still be needed), so I'm not sure why you find it less boiler-platey. But anyone who wants to understand yours, would need to know or look up what gsl::final_act is and how exactly it works.Franks
@Franks The whole point is you don't need the try/catch block (or finally) as all that would be done be the appropriate destructor. The finally example I append there is a simple alternative technique to provide finally functionality if you really want to. Normally you would not but its simple to add to C++. As for knowing what final_act does: Coming to a standard near you (C++ gsl => modernescpp.com/index.php/… )Bleach
@Franks Here is how I see it. More than happy to have a discussion around the subject if you want to.Bleach
No destructor can replace the catch block, since destructors can't catch exceptions thrown from outside them. So you can drop the finally block, but you still need try/catch (assuming you want to catch and handle the exception of course).Franks
You're right that I neglected to catch any exceptions inside the finally block. So then your code is perhaps slightly shorter. Still, just because some function is or becomes part of a standard, that doesn't mean people automatically know its exact name and signature by heart. Granted, you also need to know what finally means but it seems much easier to remember, at least to me. Maybe I'm just not familiar enough with modern C++ constructs but the [&ok]() part also requires a lot of thinking from my part...Franks
G
82

RAII is usually better, but you can have easily the finally semantics in C++. Using a tiny amount of code.

Besides, the C++ Core Guidelines give finally.

Here is a link to the GSL Microsoft implementation and a link to the Martin Moene implementation

Bjarne Stroustrup multiple times said that everything that is in the GSL it meant to go in the standard eventually. So it should be a future-proof way to use finally.

You can easily implement yourself if you want though, continue reading.

In C++11 RAII and lambdas allows to make a general finally:

namespace detail { //adapt to your "private" namespace
template <typename F>
struct FinalAction {
    FinalAction(F f) : clean_{f} {}
   ~FinalAction() { if(enabled_) clean_(); }
    void disable() { enabled_ = false; };
  private:
    F clean_;
    bool enabled_{true}; }; }

template <typename F>
detail::FinalAction<F> finally(F f) {
    return detail::FinalAction<F>(f); }

example of use:

#include <iostream>
int main() {
    int* a = new int;
    auto delete_a = finally([a] { delete a; std::cout << "leaving the block, deleting a!\n"; });
    std::cout << "doing something ...\n"; }

the output will be:

doing something...
leaving the block, deleting a!

Personally I used this few times to ensure to close POSIX file descriptor in a C++ program.

Having a real class that manage resources and so avoids any kind of leaks is usually better, but this finally is useful in the cases where making a class sounds like an overkill.

Besides, I like it better than other languages finally because if used naturally you write the closing code nearby the opening code (in my example the new and delete) and destruction follows construction in LIFO order as usual in C++. The only downside is that you get an auto variable you don't really use and the lambda syntax make it a little noisy (in my example in the fourth line only the word finally and the {}-block on the right are meaningful, the rest is essentially noise).

Another example:

 [...]
 auto precision = std::cout.precision();
 auto set_precision_back = finally( [precision, &std::cout]() { std::cout << std::setprecision(precision); } );
 std::cout << std::setprecision(3);

The disable member is useful if the finally has to be called only in case of failure. For example, you have to copy an object in three different containers, you can setup the finally to undo each copy and disable after all copies are successful. Doing so, if the destruction cannot throw, you ensure the strong guarantee.

disable example:

//strong guarantee
void copy_to_all(BIGobj const& a) {
    first_.push_back(a);
    auto undo_first_push = finally([first_&] { first_.pop_back(); });

    second_.push_back(a);
    auto undo_second_push = finally([second_&] { second_.pop_back(); });

    third_.push_back(a);
    //no necessary, put just to make easier to add containers in the future
    auto undo_third_push = finally([third_&] { third_.pop_back(); });

    undo_first_push.disable();
    undo_second_push.disable();
    undo_third_push.disable(); }

If you cannot use C++11 you can still have finally, but the code becomes a bit more long winded. Just define a struct with only a constructor and destructor, the constructor take references to anything needed and the destructor does the actions you need. This is basically what the lambda does, done manually.

#include <iostream>
int main() {
    int* a = new int;

    struct Delete_a_t {
        Delete_a_t(int* p) : p_(p) {}
       ~Delete_a_t() { delete p_; std::cout << "leaving the block, deleting a!\n"; }
        int* p_;
    } delete_a(a);

    std::cout << "doing something ...\n"; }

Hopefully you can use C++11, this code is more to show how the "C++ does not support finally" has been nonsense since the very first weeks of C++, it was possible to write this kind of code even before C++ got its name.

Gnawing answered 26/8, 2014 at 16:36 Comment(10)
There might be a possible problem: in function 'finally(F f)' it returns a object of FinalAction, so the deconstructor might be called before returning of function finally. Maybe we should use std::function instead of template F.Histogen
Note that FinalAction is basically the same as the popular ScopeGuard idiom, only with a different name.Flame
Super. Very nice style. I also think that we could use not only lambda, but inheritance with virtual destructor.Antepast
You would lose the fact that the opening and closing code are nearby, besides if you have to write your class then just use RAII.Gnawing
Is this optimization safe?Dena
Nowadays it should be supported by all major compilers. What are you are worried about?Gnawing
@Gnawing Sorry for not replying sooner, I didn't get a notification for your comment. I was worried the finally block (in which I call a DLL function) would be called before the end of the scope (because the variable is unused), but have since found a question on SO that cleared my worries. I would link to it, but unfortunately, I can't find it anymore.Dena
The disable() function is kind of a wart on your otherwise clean design. If you want the finally to be only called in case of failure, then why not just use catch statement? Isn't that what it's for?Zanze
Take my example, how would you write the code inside the catch? Inside the catch block you do not know what copy failed, first_, second_, or _ third? You can probably check somewhat, but I find it clearer like this. It might well be a matter of taste and habit.Gnawing
Would it make sense to remove the disable() method and call the function from the destructor only when called while handling an exception? ~FinalAction() { if (enabled_ && std::uncaught_exceptions() > 0) clean_(); }Magnanimous
E
37

why is it that even managed languages provide a finally-block despite resources being deallocated automatically by the garbage collector anyway?

Actually, languages based on Garbage collectors need "finally" more. A garbage collector does not destroy your objects in a timely manner, so it can not be relied upon to clean up non-memory related issues correctly.

In terms of dynamically-allocated data, many would argue that you should be using smart-pointers.

However...

RAII moves the responsibility of exception safety from the user of the object to the designer

Sadly this is its own downfall. Old C programming habits die hard. When you're using a library written in C or a very C style, RAII won't have been used. Short of re-writing the entire API front-end, that's just what you have to work with. Then the lack of "finally" really bites.

Ephebe answered 21/9, 2010 at 11:31 Comment(14)
Exactly... RAII seems nice from an ideal perspective. But I have to work with conventional C APIs all the time (like C-style functions in Win32 API...). It's very common to acquire a resource that returns some kind of a HANDLE, which then requires some function like CloseHandle(HANDLE) to clean up. Using try ... finally is a nice way of dealing with possible exceptions. (Thankfully, it looks like shared_ptr with custom deleters and C++11 lambdas should provide some RAII-based relief that doesn't require writing entire classes to wrap some API I only use in one place.).Pristine
@JamesJohnston, it's very easy to write a wrapper class that holds any kind of handle and provides RAII mechanics. ATL provides a bunch of them for example. It seems that you consider this to be too much trouble but I disagree, they're very small and easy to write.Branen
Simple yes, small no. Size is dependent on the complexity of the library you're working with.Ephebe
@MarkRansom: Is there any mechanism via which RAII can do something intelligent if an exception occurs during cleanup while another exception is pending? In systems with try/finally, it's possible--though awkward--to arrange things so that the pending exception and the exception that occurred during cleanup both get stored in a new CleanupFailedException. Is there any plausible way to achieve such a result using RAII?Latinist
@supercat, it's even worse in C++, an exception generated during exception processing can shut things down entirely. See c2.com/cgi/wiki?BewareOfExceptionsInTheDestructorBranen
@MarkRansom: I'm somewhat ambivalent as to whether the Java/.net approach of junking the existing instruction or the C++ approach of forcing a system meltdown is worse. Frankly, I consider both approaches pretty horrid. An advantage of finally, though, is that if the rest of the try block is properly written, the code within finally can know whether an exception is pending. Of course, if a language could simply provide a finally Exception ex construct with any pending exception (null if none) stored in ex, even that scenario would be much cleaner.Latinist
@couling: Dispose has nothing to do with the garbage collector, but is rather the deterministic way of notifying objects their services are no longer required. Having an explicit "cleanup on success" call, and having the default cleanup method assume it's cleaning up for an error if the "success" part didn't run first is somewhat workable, but it's icky since accidental omission of the "success" part cannot safely trigger an exception (which would otherwise be the normal method of notifying someone that a problem exists).Latinist
@couling: For resources which can implement consistent "rollback if not committed" semantics, it would probably be reasonable to have the default cleanup method perform a rollback of any non-committed transactions. If user code accidentally forgets a commit, the effects will be obvious. It's far less clear, though, what one should do for things like general-purpose files, though, where the normal semantics of Dispose would be expected to behave essentially the same as Close. If Dispose can't throw exceptions when things go wrong, it should not be usable as a normal "success" cleanup...Latinist
@couling: ...but it's not exactly clear what else it should do. For special-purpose files, one could have the first write operation which modifies a file set a "dirty" flag in the file which is only cleared by a "proper" Close, but such an approach requires that the class implementing it know about how the dirty flag, etc. will work (which could be complicated if multiple applications can access different parts of the file at once).Latinist
@Latinist oops, meant finalize which has everything to do with the GC. Was thinking of the wrong language ... see rewrite:Ephebe
@Latinist Its interesting how the different idioms make it difficult to compare. the c++ example is (in my opinion) comparable to throwing a RuntimeException on finalize() ; effectively trying to crash the garbage collector. Good choice here is to melt down. In java/.net, I find that it is best to have a separate "cleanup on error" to "cleanup on success" where I rollback vs commit and ignore(log only) vs throw exceptions. As a result I now use finally less and less. It's my belief that on no occasion should a developer allow that "nested" exception to affect program flow.Ephebe
@Latinist I understand that writing the same code twice in this way seems "icky" but my experience is that in practise, the "on success" and "on error" code blocks subtly differ so frequently that I rarely get to use finally without a number of if statements. Of these differences, exception handling is the most frequent.Ephebe
@couling: There are many cases where a program will call a SomeObject.DoSomething() method and want to know whether it (1) succeeded, (2) failed with no side-effects, (3) failed with side-effects the caller is prepared to cope with, or (4) failed with side-effects the caller cannot cope with. Only the caller is going to know what situations it can and cannot cope with; what the caller needs is a way of knowing what the situation is. It's too bad there's no standard mechanism for supplying the most important information about an exception.Latinist
@couling: It doesn't have to be long. One never said you had to wrap the entire library. Just have a MyResource class that initializes the handle in its constructor, releases it in its destructor and has a getHandle() class for you to use the API. It's perhaps not the nicest ever, but it's RAII for your C library and it will take ~20 lines at most (it may cause more changes in the calling code and if you think that's too wordy, overloading dereferencing may be appropriate)Diatomic
B
35

Beyond making clean up easy with stack-based objects, RAII is also useful because the same 'automatic' clean up occurs when the object is a member of another class. When the owning class is destructed, the resource managed by the RAII class gets cleaned up because the dtor for that class gets called as a result.

This means that when you reach RAII nirvana and all members in a class use RAII (like smart pointers), you can get away with a very simple (maybe even default) dtor for the owner class since it doesn't need to manually manage its member resource lifetimes.

Bobbitt answered 2/10, 2008 at 7:28 Comment(1)
That's a very good point. +1 to you. Not many other people have voted you up though. I hope you don't mind that I edited my post to include your comments. (I gave you credit of course.) Thanks! :)Terce
B
12

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(); });

    ...
Beeck answered 30/11, 2017 at 13:14 Comment(0)
N
7

Sorry for digging up such an old thread, but there is a major error in the following reasoning:

RAII moves the responsibility of exception safety from the user of the object to the designer (and implementer) of the object. I would argue this is the correct place as you then only need to get exception safety correct once (in the design/implementation). By using finally you need to get exception safety correct every time you use an object.

More often than not, you have to deal with dynamically allocated objects, dynamic numbers of objects etc. Within the try-block, some code might create many objects (how many is determined at runtime) and store pointers to them in a list. Now, this is not an exotic scenario, but very common. In this case, you'd want to write stuff like

void DoStuff(vector<string> input)
{
  list<Foo*> myList;

  try
  {    
    for (int i = 0; i < input.size(); ++i)
    {
      Foo* tmp = new Foo(input[i]);
      if (!tmp)
        throw;

      myList.push_back(tmp);
    }

    DoSomeStuff(myList);
  }
  finally
  {
    while (!myList.empty())
    {
      delete myList.back();
      myList.pop_back();
    }
  }
}

Of course the list itself will be destroyed when going out of scope, but that wouldn't clean up the temporary objects you have created.

Instead, you have to go the ugly route:

void DoStuff(vector<string> input)
{
  list<Foo*> myList;

  try
  {    
    for (int i = 0; i < input.size(); ++i)
    {
      Foo* tmp = new Foo(input[i]);
      if (!tmp)
        throw;

      myList.push_back(tmp);
    }

    DoSomeStuff(myList);
  }
  catch(...)
  {
  }

  while (!myList.empty())
  {
    delete myList.back();
    myList.pop_back();
  }
}

Also: why is it that even managed lanuages provide a finally-block despite resources being deallocated automatically by the garbage collector anyway?

Hint: there's more you can do with "finally" than just memory deallocation.

Narceine answered 2/6, 2010 at 14:25 Comment(7)
Managed languages need finally-blocks precisely because only one kind of resource is automatically managed: memory. RAII means that all resources can be handled in the same way, so no need for finally. If you actually used RAII in your example (by using smart pointers in your list instead of naked ones), the code would be simpler than your "finally"-example. And even simpler if you don't check the return value of new - checking it is pretty much pointless.Fluency
new doesn't return NULL, it throws an exception insteadCullender
You raise an important question, but it does have 2 possible answers. One is that given by Myto -- use smart pointers for all dynamic allocations. The other is to use standard containers, which always destroy their contents upon destruction. Either way, every allocated object is ultimately owned by a statically allocated object which automatically frees it upon destruction. It's a real shame that these better solutions are hard for programmers to discover because of the high visibility of plain pointers and arrays.Officiant
C++11 improves this and includes std::shared_ptr and std::unique_ptr directly in the stdlib.Indecency
void DoStuff(const vector<string>& input) { list<shared_ptr<Foo>> myList; for (int i = 0; i < input.size(); ++i) { auto tmp = make_shared<Foo>(input[i]); myList.push_back(tmp); } DoSomething(myList); }Blueness
The reason your example is so horrid looking isn't because RAII is flawed, rather it is because you failed to use it. Raw pointers are not RAII.Lanciform
Noone is going to rewrite established code to make full textbook use of RAII, even if they fully understood all of it's nuances. The finally block is a useful construct that allows programmers to write shorter code that performs the required cleanup of resources, without going into "layers-of-abstraction-hell". It's a lot nicer - and more readable - to catch an exception, do something with it, perhaps rethrow it, and know that the finally will always run for you, rather than setting some flags in catch{}, freeing the resources, then checking the flags and acting on them. I hate flag soup.Sheave
P
6

FWIW, Microsoft Visual C++ does support try,finally and it has historically been used in MFC apps as a method of catching serious exceptions that would otherwise result in a crash. For example;

int CMyApp::Run() 
{
    __try
    {
        int i = CWinApp::Run();
        m_Exitok = MAGIC_EXIT_NO;
        return i;
    }
    __finally
    {
        if (m_Exitok != MAGIC_EXIT_NO)
            FaultHandler();
    }
}

I've used this in the past to do things like save backups of open files prior to exit. Certain JIT debugging settings will break this mechanism though.

Pyrites answered 2/10, 2008 at 7:25 Comment(3)
bear in mind that's not really C++ exceptions, but SEH ones. You can use both in MS C++ code. SEH is an OS exception handler that is the way VB, .NET implement exceptions.Skimpy
and you can use SetUnhandledExceptionHandler to create a 'global' un-catched exception handler - for SEH exceptions.Skimpy
SEH is horrible and also prevents C++ destructors from being calledChristianchristiana
M
6

As pointed out in the other answers, C++ can support finally-like functionality. The implementation of this functionality that is probably closest to being part of the standard language is the one accompanying the C++ Core Guidelines, a set of best practices for using C++ edited by Bjarne Stoustrup and Herb Sutter. An implementation of finally is part of the Guidelines Support Library (GSL). Throughout the Guidelines, use of finally is recommended when dealing with old-style interfaces, and it also has a guideline of its own, titled Use a final_action object to express cleanup if no suitable resource handle is available.

So, not only does C++ support finally, it is actually recommended to use it in a lot of common use-cases.

An example use of the GSL implementation would look like:

#include <gsl/gsl_util.h>

void example()
{
    int handle = get_some_resource();
    auto handle_clean = gsl::finally([&handle] { clean_that_resource(handle); });

    // Do a lot of stuff, return early and throw exceptions.
    // clean_that_resource will always get called.
}

The GSL implementation and usage is very similar to the one in Paolo.Bolzoni's answer. One difference is that the object created by gsl::finally() lacks the disable() call. If you need that functionality (say, to return the resource once it's assembled and no exceptions are bound to happen), you might prefer Paolo's implementation. Otherwise, using GSL is as close to using standardized features as you will get.

Mckim answered 8/8, 2018 at 4:45 Comment(0)
P
5

I have a use case where I think finally should be a perfectly acceptable part of the C++11 language, as I think it is easier to read from a flow point of view. My use case is a consumer/producer chain of threads, where a sentinel nullptr is sent at the end of the run to shut down all threads.

If C++ supported it, you would want your code to look like this:

    extern Queue downstream, upstream;

    int Example()
    {
        try
        {
           while(!ExitRequested())
           {
             X* x = upstream.pop();
             if (!x) break;
             x->doSomething();
             downstream.push(x);
           } 
        }
        finally { 
            downstream.push(nullptr);
        }
    }

I think this is more logical that putting your finally declaration at the start of the loop, since it occurs after the loop has exited... but that is wishful thinking because we can't do it in C++. Note that the queue downstream is connected to another thread, so you can't put in the sentinel push(nullptr) in the destructor of downstream because it can't be destroyed at this point... it needs to stay alive until the other thread receives the nullptr.

So here is how to use a RAII class with lambda to do the same:

    class Finally
    {
    public:

        Finally(std::function<void(void)> callback) : callback_(callback)
        {
        }
        ~Finally()
        {
            callback_();
        }
        std::function<void(void)> callback_;
    };

and here is how you use it:

    extern Queue downstream, upstream;

    int Example()
    {
        Finally atEnd([](){ 
           downstream.push(nullptr);
        });
        while(!ExitRequested())
        {
           X* x = upstream.pop();
           if (!x) break;
           x->doSomething();
           downstream.push(x);
        }
    }
Paulapauldron answered 1/12, 2015 at 1:1 Comment(1)
Hi, I believe my answer above (https://mcmap.net/q/24807/-does-c-support-39-finally-39-blocks-and-what-39-s-this-39-raii-39-i-keep-hearing-about) fully satisfies your requirements.Rusticus
R
4

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. :)

Rusticus answered 1/8, 2016 at 14:32 Comment(6)
@MarkLakata, I updated the post with a better implementation which supports throwing exceptions and returns.Rusticus
Looks good. You could get rid of Caveat 2 by just putting in an impossible catch(xxx) {} block at the start of the finally macro, where xxx is a bogus type just for the purposes of having at least one catch block.Paulapauldron
@MarkLakata, I thought of that too, but that would make it impossible to use catch(...), wouldn't it?Rusticus
I don't think so. Just make up an obscure type xxx in a private namespace that will never be used.Paulapauldron
Gcc spits out finally.cpp:60:5: error: ‘...’ handler must be the last handler for its try block. Clang does the same. I believe the standard just forbids to have a catch(...) block in the middle.Rusticus
I understand your point now (I missed it the first time). Maybe the c++ gods have declared this is just not meant to be :)Paulapauldron
Z
3

Not really, but you can emulate them to some extend, for example:

int * array = new int[10000000];
try {
  // Some code that can throw exceptions
  // ...
  throw std::exception();
  // ...
} catch (...) {
  // The finally-block (if an exception is thrown)
  delete[] array;
  // re-throw the exception.
  throw; 
}
// The finally-block (if no exception was thrown)
delete[] array;

Note that the finally-block might itself throw an exception before the original exception is re-thrown, thereby discarding the original exception. This is the exact same behavior as in a Java finally-block. Also, you cannot use return inside the try&catch blocks.

Zymo answered 30/5, 2014 at 19:36 Comment(3)
I'm glad that you mentioned the finally block might throw; it's the thing that most of the "use RAII" answers seem to ignore. To avoid having to write the finally block twice, you could do something like std::exception_ptr e; try { /*try block*/ } catch (...) { e = std::current_exception(); } /*finally block*/ if (e) std::rethrow_exception(e);Grisham
That's all I wanted to know! Why none of the other answers explained that a catch(...) + empty throw; works almost like a finally block? Sometimes you just need it.Transient
The solution I provided in my answer (https://mcmap.net/q/24807/-does-c-support-39-finally-39-blocks-and-what-39-s-this-39-raii-39-i-keep-hearing-about) should allow for throwing exceptions from inside the finally block.Rusticus
P
1

As many people have stated, the solution is to use C++11 features to avoid finally blocks. One of the features is unique_ptr.

Here is Mephane's answer written using RAII patterns.

#include <vector>
#include <memory>
#include <list>
using namespace std;

class Foo
{
 ...
};

void DoStuff(vector<string> input)
{
    list<unique_ptr<Foo> > myList;

    for (int i = 0; i < input.size(); ++i)
    {
      myList.push_back(unique_ptr<Foo>(new Foo(input[i])));
    }

    DoSomeStuff(myList);
}

Some more introduction to using unique_ptr with C++ Standard Library containers is here

Paulapauldron answered 9/7, 2014 at 21:7 Comment(0)
D
1

I also think that RIIA is not a fully useful replacement for exception handling and having a finally. BTW, I also think RIIA is a bad name all around. I call these types of classes 'janitors' and use them a LOT. 95% of the time they are neither initializing nor acquiring resources, they are applying some change on a scoped basis, or taking something already set up and making sure it's destroyed. This being the official pattern name obsessed internet I get abused for even suggesting my name might be better.

I just don't think it's reasonable to require that that every complicated setup of some ad hoc list of things has to have a class written to contain it in order to avoid complications when cleaning it all back up in the face of needing to catch multiple exception types if something goes wrong in the process. This would lead to lots of ad hoc classes that just wouldn't be necessary otherwise.

Yes it's fine for classes that are designed to manage a particular resource, or generic ones that are designed to handle a set of similar resources. But, even if all of the things involved have such wrappers, the coordination of cleanup may not just be a simple in reverse order invocation of destructors.

I think it makes perfect sense for C++ to have a finally. I mean, jeez, so many bits and bobs have been glued onto it over the last decades that it seems odd folks would suddenly become conservative over something like finally which could be quite useful and probably nothing near as complicated as some other things that have been added (though that's just a guess on my part.)

Denny answered 18/12, 2018 at 19:28 Comment(0)
P
0

EDITED

If you are not breaking/continuing/returning etc., you could just add a catch to any unknown exception and put the always code behind it. That is also when you don't need the exception to be re-thrown.

try{
   // something that might throw exception
} catch( ... ){
   // what to do with uknown exception
}

//final code to be called always,
//don't forget that it might throw some exception too
doSomeCleanUp(); 

So what's the problem?

Normally finally in other programming languages usually runs no matter what(usually meaning regardless of any return, break, continue, ...) except for some sort of system exit() - which differes a lot per programming language - e.g. PHP and Java just exit in that moment, but Python executes finally anyways and then exits.

But the code I've described above doesn't work that way
=> following code outputs ONLY something wrong!:

#include <stdio.h>
#include <iostream>
#include <string>

std::string test() {
    try{
       // something that might throw exception
       throw "exceptiooon!";

       return "fine";
    } catch( ... ){
       return "something wrong!";
    }
    
    return "finally";
}

int main(void) {
    
    std::cout << test();
    
    
    return 0;
}
Picrotoxin answered 2/9, 2015 at 9:23 Comment(2)
This doesn't work, because the whole point of a finally block is to perform cleanup even when the code should allow an exception to leave the code block. Consider: ` try { // stuff possibly throwing "B" } catch (A & a) { } finally { // if C++ had it... // stuff that must happen, even if "B" is thrown. } // won't execute if "B" is thrown. ` IMHO, the point of exceptions is to reduce error-handling code, so catch blocks, wherever a throw might occur, is counterproductive. This is why RAII helps: if applied liberally, exceptions matter most at the top and bottom layers.Staciestack
@Staciestack altough your opinion is not holy, I get the point, but in C++ is no such thing so you have to consider this as a top layer that emulates this behavior.Picrotoxin
H
-2
try
{
  ...
  goto finally;
}
catch(...)
{
  ...
  goto finally;
}
finally:
{
  ...
}
Holeandcorner answered 23/4, 2010 at 19:28 Comment(3)
Cute idiom, but its not quite the same. returning in the try block or catch won't pass through your 'finally:' code.Xiaoximena
It's worth keeping this wrong answer (with 0 rating), since Edward Kmett brings up a very important distinction.Paulapauldron
Even bigger flaw (IMO): This code eats all exceptions, which finally does not do.Lanciform

© 2022 - 2024 — McMap. All rights reserved.