Does C++ support 'finally' blocks?
What is the RAII idiom?
What is the difference between C++'s RAII idiom and C#'s 'using' statement?
Does C++ support 'finally' blocks?
What is the RAII idiom?
What is the difference between C++'s RAII idiom and C#'s 'using' statement?
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.
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 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 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 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 finally
support is not needed because C++ supports destructors. Destructors can be coerced into doing anything a finally
block could do. –
Cartogram 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.
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.
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
// 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 return
s in the loading part, so I don't have to do a lot of if
s 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 goto
s instead of the return
s, 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=finally –
Superb 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 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 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 final_act
does: Coming to a standard near you (C++ gsl => modernescpp.com/index.php/… ) –
Bleach 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 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.
FinalAction
is basically the same as the popular ScopeGuard
idiom, only with a different name. –
Flame 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.
CleanupFailedException
. Is there any plausible way to achieve such a result using RAII? –
Latinist 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 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 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 finalize
which has everything to do with the GC. Was thinking of the wrong language ... see rewrite: –
Ephebe 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 if
statements. Of these differences, exception handling is the most frequent. –
Ephebe 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 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 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.
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(); });
...
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.
new
doesn't return NULL, it throws an exception instead –
Cullender std::shared_ptr
and std::unique_ptr
directly in the stdlib. –
Indecency 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.
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.
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);
}
}
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:
break
statement from within the try
and catch()
's blocks, since they live within a lambda function;catch()
block after the try
: it's a C++ requirement; 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. :)
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 catch(...)
, wouldn't it? –
Rusticus xxx
in a private namespace that will never be used. –
Paulapauldron 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 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.
std::exception_ptr e; try { /*try block*/ } catch (...) { e = std::current_exception(); } /*finally block*/ if (e) std::rethrow_exception(e);
–
Grisham finally
block. –
Rusticus 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
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.)
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();
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;
}
try
{
...
goto finally;
}
catch(...)
{
...
goto finally;
}
finally:
{
...
}
finally
does not do. –
Lanciform © 2022 - 2024 — McMap. All rights reserved.