For many RAII "guard" classes, being instantiated as anonymous variables does not make sense at all:
{
std::lock_guard<std::mutex>{some_mutex};
// Does not protect the scope!
// The unnamed instance is immediately destroyed.
}
{
scope_guard{[]{ cleanup(); }};
// `cleanup()` is executed immediately!
// The unnamed instance is immediately destroyed.
}
From this article:
Anonymous variables in C++ have “expression scope”, meaning they are destroyed at the end of the expression in which they are created.
Is there any way to prevent the user from instantiating them without a name? ("Prevent" may be too strong - "making it very difficult" is also acceptable).
I can think of two possible workarounds, but they introduce syntactical overhead in the use of the class:
Hide the class in a
detail
namespace and provide a macro.namespace detail { class my_guard { /* ... */ }; }; #define SOME_LIB_MY_GUARD(...) \ detail::my_guard MY_GUARD_UNIQUE_NAME(__LINE__) {__VA_ARGS__}
This works, but is hackish.
Only allow the user to use the guard through an higher-order function.
template <typename TArgTuple, typename TF> decltype(auto) with_guard(TArgTuple&& guardCtorArgs, TF&& f) { make_from_tuple<detail::my_guard>(std::forward<TArgTuple>(guardCtorArgs)); f(); }
Usage:
with_guard(std::forward_as_tuple(some_mutex), [&] { // ... });
This workaround does not work when the initialization of the guard class has "fluent" syntax:
{ auto _ = guard_creator() .some_setting(1) .some_setting(2) .create(); }
Is there any better alternative? I have access to C++17 features.
lock_guard
exists and why should it stay alive as long as the scope it protects stands. trying to enforce this via API or internal implementation is just redundant.. – Sightlesslock_guard
example, I agree. I was working on some non-allocation async chain generation with "fluent" syntax though, where it's very natural to have anonymous chains. But you still need a name, otherwise the storage for the chain dies too quickly. It's not as obvious as thelock_guard
, and I'd like to prevent this mistake. – Dumahstd::async
+future::then
? – Sightlessmake_lock_guard
before C++17. One possibility is to force the use of amake_
function and then mark it[[nodiscard]]
. – Timmy