I want to implement a finally
block in my C++ program, and the language certainly has the tools to do it if not a native facility. I was wondering what the best way to do this is?

- 9,237
- 4
- 32
- 49

- 134,909
- 25
- 265
- 421
-
was waiting for this one..thank you.. – Koushik Shetty Jun 28 '13 at 02:27
-
Some C++ compilers, like C++Builder, actually do implement `finally` as a native compiler extension. – Remy Lebeau Jun 28 '13 at 03:05
-
Some previous attempts: http://stackoverflow.com/questions/14897392/are-there-issues-with-this-scope-guard-implementation, http://stackoverflow.com/questions/3669833/c11-scope-exit-guard-a-good-idea, http://stackoverflow.com/questions/10270328/the-simplest-and-neatest-c11-scopeguard. – kennytm Jun 28 '13 at 09:16
-
Note that there is a bit more lightweight solution possible: http://codereview.stackexchange.com/questions/19730/scope-exit-something-wrong – user1095108 Jun 28 '13 at 09:47
-
@user1095108 Is that answer identical to Boost.ScopeExit? Also, that's not lighter weight; it's almost identical at the core but not exception-safe, and seems to have some extra features I can't decipher. It appears to be a port from C++03 code, but no longer compatible with C++03. – Potatoswatter Jun 28 '13 at 09:51
-
@Potatoswatter You're right, exception safety is not my concern usually. I let them happen and I stay away from Boost.ScopeExit these days. – user1095108 Jun 28 '13 at 10:54
-
@RemyLebeau as you've noted on another question, `__finally` in C++Builder does not execute until after local variables to the function have been destroyed, if execution of the associated `try` blocks reaches a `return` statement. IDK whether MSVC has the same "feature"; the solutions posted on this thread allow partial control of this by the decision whether to instantiate the lambda before or after local variables. – M.M Dec 22 '14 at 04:56
-
Here is an implementation of finally block based entirely on lambda functions (no classes are used at all): https://stackoverflow.com/a/47574378/5447906 – anton_rh Nov 30 '17 at 13:32
2 Answers
This simple implementation seems to be 100% safe.
template< typename t >
class sentry {
t o;
public:
sentry( t in_o ) : o( std::move( in_o ) ) {}
sentry( sentry && ) = delete;
sentry( sentry const & ) = delete;
~ sentry() noexcept {
static_assert( noexcept( o() ),
"Please check that the finally block cannot throw, "
"and mark the lambda as noexcept." );
o();
}
};
template< typename t >
sentry< t > finally( t o ) { return { std::move( o ) }; }
The noexcept
is important because you don't want to throw an exception when your function is already exiting due to an exception. (That leads to immediate termination.) C++ doesn't check that the lambda really can't throw anything; you manually check and mark it noexcept
. (See below.)
The factory function is necessary because otherwise there's no way to obtain a type dependent on a lambda.
The copy and move constructors must be deleted because they could be used to implicitly generate a temporary object, which would implement another sentry, which would call the block prematurely upon destruction. But the default assignment operator is left intact because if you already have two sentries that do different things, it's OK to assign them. (Somewhat theoretical, but whatever.)
It would be nice if the constructor were explicit
, but that seems to preclude in-place initialization of the return value. Since the class is not movable, the object living in the caller's scope must be initialized directly by the expression in the return
statement.
To use, just define a guard like this:
auto && working_state_guard = finally( [&]() noexcept {
reset_working_state();
} );
It's essential to bind to a reference, because declaring a real object in the calling scope would require move-initializing that object from the function return value.
Circa version 4.7, g++ -Wall
would give a warning that the guard is unused. Whether or not you're coding against that, you can add a little safety and documentation at the end of the function with an idiom:
static_cast< void >( working_state_guard );
This lets the reader know about execution of code from the beginning of the scope, and it can serve as a reminder to double-check when copy-pasting code.
Usage.
int main() {
auto && guard = finally( []() noexcept {
try {
std::cout << "Goodbye!\n";
} catch ( ... ) {
// Throwing an exception from here would be worse than *anything*.
}
} );
std::cin.exceptions( std::ios::failbit );
try {
float age;
std::cout << "How old are you?\n";
std::cin >> age;
std::cout << "You are " << age << " years (or whatever) old\n";
} catch ( std::ios::failure & ) {
std::cout << "Sorry, didn't understand that.\n";
throw;
}
static_cast< void >( guard );
}
This produces output like
$ ./sentry
How old are you?
3
You are 3 years (or whatever) old.
Goodbye!
$ ./sentry
How old are you?
four
Sorry, didn't understand that.
Goodbye!
terminate called after throwing an instance of 'std::ios_base::failure'
what(): basic_ios::clear
Abort trap: 6
How to cancel the action from being performed?
Looking at some of the "previous attempts," I see a transactional commit()
method. I don't think that belongs in the ScopeGuard/finally block implementation. Implementing a protocol is the responsibility of the contained functor, so the correct division of labor would be to encapsulate a Boolean flag in it, such as by capturing a bool
local flag, and flipping the flag when the transaction is complete.
Likewise trying to cancel the action by reassigning the functor itself is just a messy approach. Generally prefer an extra case inside the existing protocol, to inventing a new protocol around the old one.

- 134,909
- 25
- 265
- 421
-
-
1Also you might want to provide a more complete example usage. Perhaps a main function containing a try/catch with the example finally usage embedded. – Andrew Tomazos Jun 28 '13 at 03:46
-
@user1131467 Thanks, just a copy-paste error. And maybe after lunch. – Potatoswatter Jun 28 '13 at 04:13
-
I don't understand why you disabled the move constructor. If you remove copy semantics from a class, there are good chances that it can still have move semantics. (Your explanation for removing copy semantics is sane, but move semantics gets none) I understand that the o member would have to be std::optional or boost::optional in that case, to allow for a resourceless state. Maybe you should add an extra justification for removing the move constructor. – Laurent LA RIZZA Jun 28 '13 at 04:48
-
@LaurentLARIZZA There is no difference between copy and move construction. The problem is that *either* would get you two objects without having called `finally` twice. Since `optional` isn't a functor, it wouldn't work. (Or if it is, calling it while empty would surely throw an exception, which renders it useless.) Given an `optional_functor` with a no-op moved-from state, your logic holds, but we don't have that here and there's no reason to suppose the user would provide such a thing. – Potatoswatter Jun 28 '13 at 06:40
-
@Potatoswatter: Of course, making the functor optional would mean modifying the destructor to do a no-op in case it is not set. And there is a difference between copy and move: move-constructing should steal the functor from the moved object, therefore unsetting it from the move object. You're right, since the aim is to emulate a finally clause, it makes no sense moving the object. I just underlined this because you only justify the absence of a copy constructor in your answer, not the absence of a move constructor. – Laurent LA RIZZA Jun 28 '13 at 08:49
-
@LaurentLARIZZA I said "The copy and move constructors must be deleted because copying would create …", but meant copying or moving. Will fix. Anyway the specifics are besides the point; we just want to prevent objects being accidentally created, period. – Potatoswatter Jun 28 '13 at 09:28
-
-
FWIW: I found this Q&A after seeing similar `finally(lambda)` syntax that had me confused. `auto _ = finally([f] { fclose(f); }) // remember to close the file` Ref: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#r12-immediately-give-the-result-of-an-explicit-resource-allocation-to-a-manager-object – kevinarpe Aug 02 '16 at 05:54
An alternative solution using std::function. No factory function needed. No per-use template instantiation (better footprint?!). No std::move and && stuff needed, no auto needed ;)
class finally
{
std::function<void()> m_finalizer;
finally() = delete;
public:
finally( const finally& other ) = delete;
finally( std::function<void()> finalizer )
: m_finalizer(finalizer)
{
}
~finally()
{
std::cout << "invoking finalizer code" << std::endl;
if( m_finalizer )
m_finalizer();
}
};
Usage:
int main( int argc, char * argv[] )
{
bool something = false;
try
{
try
{
std::cout << "starting" << std::endl;
finally final([&something]() { something = true; });
std::cout << "throwing" << std::endl;
throw std::runtime_error("boom");
}
catch(std::exception & ex )
{
std::cout << "inner catch" << std::endl;
throw;
}
}
catch( std::exception & ex )
{
std::cout << "outer catch" << std::endl;
if( something )
{
std::cout << "works!" << std::endl;
}
else
{
std::cout << "NOT working!" << std::endl;
}
}
std::cout << "exiting" << std::endl;
return 0;
}
Output:
starting
throwing
invoking finalizer code
inner catch
outer catch
works!
exiting

- 10,905
- 5
- 32
- 53
-
This adds the runtime overhead of an indirect function call, and the template instantiation overhead of wrapping the lambda inside `std::function`. Although hidden by type erasure, the templates still exist. Also, the copy constructor here will cause the lambda to be called twice. You should delete the copy constructor, and perhaps provide a move constructor if it's needed (which it doesn't seem to be). – Potatoswatter Dec 22 '14 at 07:21
-
Run the program and see - it is not running the lanbda twice. The destructor invokes the lambda and as you can see in the printed output of the example, the ``~finally()'' print only shows once. As for template instantiation - yes there is 1 instantation, but not 1 per use. In the other solution, the templates are instatiated whenever the capture expression changes. Both for factory and for the sentry class. Removing copy constructor is not possible as silly c++11 produces an error if I try to pass the function as a reference. I ran my test on freebsd 10.1 with clang, btw. – BitTickler Dec 22 '14 at 20:02
-
Forget what I said about the copy constructor...it is a leftover of previous versions. – BitTickler Dec 22 '14 at 20:35
-
The instantiations inside `std::function` include at least the conversion constructor (corresponding to the factory function) and a hidden container class which provides indirect calling semantics (corresponding to the sentry class, but more complex). These occur once per distinct lambda, or "per use." Anyway, now this is a valid solution so +1 :) – Potatoswatter Dec 23 '14 at 05:07
-
The one thing which still worries me is the execution order of try, catch and finally code sections. If I am not mistaken, in other languages the finally section is executed AFTER the catch code execution while in both solutions shown here, finally code is executed before the catch code section. – BitTickler Dec 23 '14 at 12:04
-
2In other languages, `finally` introduces a block of code. In C++, it's an object declaration. The code is executed at the end of the object's scope, so if you want it to happen after the `catch`, just declare it before the `try`. – Potatoswatter Dec 23 '14 at 14:58
-
The constructor should be `explicit` and it should move the `std::function` instead of copying. The assignment operator should also be deleted if you want `finally` to be completely non-copyable. Furthermore, the default constructor is already implicitly deleted. – Emile Cormier Jun 12 '17 at 20:37