Recently, I came across an issue about the design of scope guard. A scope guard invokes a supplied function object (usually performs cleanup procedures) upon exiting the enclosing scope. The current design is as follows:
#define HHXX_ON_SCOPE_EXIT_F(...) ...
#define HHXX_ON_SCOPE_EXIT(...) HHXX_ON_SCOPE_EXIT_F([&]() { __VA_ARGS__ })
HHXX_ON_SCOPE_EXIT_F(...)
executes the function object as defined by __VA_ARGS__
upon exiting the enclosing scope. For example,
int i = 0;
{
HHXX_ON_SCOPE_EXIT_F([&]() {
assert(++i == 4);
});
HHXX_ON_SCOPE_EXIT_F([&]() {
assert(++i == 3);
});
HHXX_ON_SCOPE_EXIT(
assert(++i == 2);
);
HHXX_ON_SCOPE_EXIT(
assert(++i == 1);
);
}
assert(i == 4);
The implementation is also simple:
#define HHXX_ON_SCOPE_EXIT_F(...) \
auto HHXX_UNIQUE_NAME(hhxx_scope_guard) = \
make_scope_guard(__VA_ARGS__)
#define HHXX_ON_SCOPE_EXIT(...) HHXX_ON_SCOPE_EXIT_F([&]() { __VA_ARGS__ })
template <typename F>
class scope_guard {
public:
explicit scope_guard(F f)
: f_(std::move(f)) {
// nop
}
~scope_guard() {
f_();
}
private:
F f_;
};
template <typename F>
auto make_scope_guard(F f) {
return scope_guard<F>(std::move(f));
}
As you can see, it doesn't provide built-in support for a method to abandon the invocation at scope exit. Providing such a feature, however, invalidates conciseness and simplicity of the current design. It also induces certain performance overhead. Basically, I'm in favor of maintaining the current design and rejecting the feature proposal. I want to hear opinions from you, so as to be sure I'm making a right decision.