patterncppMinor
C++ finalizer template
Viewed 0 times
finalizertemplatestackoverflow
Problem
Consider, please, my code of the finalizer template:
In particular I would enhance this template to avoid of using a typenames twice. Let's say we need to close some file on leaving some block of code. Then we declare an object:
Here I used the standard
#include
template
class finally
{
public:
finally(F action, const Args&... args) :
_action(std::bind(action, args...))
{}
~finally()
{
if(enabled)
_action();
}
bool enabled = true;
private:
std::function _action;
};In particular I would enhance this template to avoid of using a typenames twice. Let's say we need to close some file on leaving some block of code. Then we declare an object:
finally f(close, some_file);Here I used the standard
close function as an action. But I should use int twice in the ``. Is there any way to avoid this?Solution
You can avoid specifying argument types twice by employing a constructor template:
But that's not everything. The
To void this issue, consider using perfect forwarding (as well as ditching
Another thing worth considering is the exception safety of
And yes, even with all these fixes, the semantics of
Edit: full code - https://ideone.com/iThn0i
template
class finally
{
public:
template
finally(F action, const Args&... args) { /* business as usual */ }
...
};But that's not everything. The
std::bind's arguments are either copied or moved, they are never passed by reference. Thus, despite const Args&... args, you might end up copying your arguments.To void this issue, consider using perfect forwarding (as well as ditching
std::bind):template
finally(F action, Args&&... args) :
_action([action, &args...]{ action(std::forward(args)...); }) {}Another thing worth considering is the exception safety of
action. Since you're invoking it in a destructor, you're risking facing std::terminate if it throws. A small try block will fix it. Also, as of now, enabled seems redundant.And yes, even with all these fixes, the semantics of
finally seems rather unpleasant compared to more traditional scope guards. At least to me.Edit: full code - https://ideone.com/iThn0i
Code Snippets
template<typename F>
class finally
{
public:
template<typename... Args>
finally<F>(F action, const Args&... args) { /* business as usual */ }
...
};template<typename... Args>
finally<F>(F action, Args&&... args) :
_action([action, &args...]{ action(std::forward<Args>(args)...); }) {}Context
StackExchange Code Review Q#133902, answer score: 4
Revisions (0)
No revisions yet.