Для многих классов RAII "guard" , созданных как анонимные переменные, не имеет никакого смысла:
{
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.
}
Из в этой статье:
Анонимные переменные в С++ имеют "область видимости", то есть они уничтожаются в конце выражения, в котором они созданы.
Есть ли способ запретить пользователю создавать экземпляры без имени? ( "Предотвращение" может быть слишком сильным - "сделать это очень сложно" ).
Я могу думать о двух возможных обходных решениях, но они вводят синтаксические накладные расходы при использовании класса:
-
Скрыть класс в пространстве имен
detail
и предоставить макрос.namespace detail { class my_guard { /* ... */ }; }; #define SOME_LIB_MY_GUARD(...) \ detail::my_guard MY_GUARD_UNIQUE_NAME(__LINE__) {__VA_ARGS__}
Это работает, но хаки.
-
Разрешить пользователю пользоваться защитой через функцию более высокого порядка.
template <typename TArgTuple, typename TF> decltype(auto) with_guard(TArgTuple&& guardCtorArgs, TF&& f) { make_from_tuple<detail::my_guard>(std::forward<TArgTuple>(guardCtorArgs)); f(); }
Использование:
with_guard(std::forward_as_tuple(some_mutex), [&] { // ... });
Это обходное решение не работает, когда инициализация класса защиты имеет "свободный" синтаксис:
{ auto _ = guard_creator() .some_setting(1) .some_setting(2) .create(); }
Есть ли лучшая альтернатива? У меня есть доступ к возможностям С++ 17.