wwa-scope-action 1.0.0
Scope guard utilities for managing exit actions in C++
scope_action.h
Go to the documentation of this file.
1#ifndef A2100C2E_3B3D_4875_ACA4_BFEF2E5B6120
2#define A2100C2E_3B3D_4875_ACA4_BFEF2E5B6120
3
4/**
5 * @file
6 * @brief Scope guard utilities for managing exit actions.
7 *
8 * This file provides the implementation of scope guards that execute specified actions
9 * when a scope is exited. The scope guards include:
10 * - `exit_action`: Executes an action when the scope is exited.
11 * - `fail_action`: Executes an action when the scope is exited due to an exception.
12 * - `success_action`: Executes an action when the scope is exited normally.
13 *
14 * These utilities are useful for ensuring that resources are properly released or
15 * actions are taken when a scope is exited, regardless of how the exit occurs.
16 *
17 * Examples:
18 * @snippet{trimleft} scope_action.cpp Using exit_action: runs on scope exit (success or exception)
19 * @snippet{trimleft} scope_action.cpp Using fail_action: runs only if an exception occurs
20 * @snippet{trimleft} scope_action.cpp Using success_action: runs only if no exception occurs
21 *
22 * @note Constructing these scope guards with dynamic storage duration might lead to
23 * unexpected behavior.
24 */
25
26#include <concepts>
27#include <exception>
28#include <limits>
29#include <type_traits>
30#include <utility>
31
32/** @brief Library namespace. */
33namespace wwa::utils {
34
35/// @cond INTERNAL
36
37namespace detail {
38
39template<typename Self, typename What, typename From>
40concept can_construct_from = !std::is_same_v<std::remove_cvref_t<From>, Self> && std::constructible_from<What, From>;
41
42template<typename Self, typename What, typename From>
43concept can_move_construct_from_noexcept = can_construct_from<Self, What, From> && !std::is_lvalue_reference_v<From> &&
44 std::is_nothrow_constructible_v<What, From>;
45
46template<typename T>
47T&& conditional_forward(T&& t, std::true_type)
48{
49 return std::forward<T>(t);
50}
51
52template<typename T>
53const T& conditional_forward(T&& t, std::false_type) // NOLINT(cppcoreguidelines-missing-std-forward)
54{
55 return t;
56}
57
58} // namespace detail
59
60/// @endcond
61
62/**
63 * @brief A scope guard that calls its exit function on destruction, when a scope is exited.
64 *
65 * An `exit_action` may be either active (i.e., it will calls its exit function on destruction),
66 * or inactive (it does nothing on destruction). An `exit_action` is active after construction from an exit function.
67 *
68 * An `exit_action` becomes inactive by calling `release()` or a move constructor. An inactive `exit_action`
69 * may also be obtained by initializing with another inactive `exit_action`. Once an `exit_action` is inactive,
70 * it cannot become active again.
71 *
72 * Usage example:
73 * @snippet{trimleft} scope_action.cpp Using exit_action: runs on scope exit (success or exception)
74 *
75 * @tparam ExitFunc Exit function type. Func is either a
76 * [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible)
77 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) type, or an lvalue reference to a
78 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) or function.
79 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit
80 * @see https://github.com/microsoft/GSL/blob/main/docs/headers.md#user-content-H-util-final_action
81 * @note Constructing an `exit_action` of dynamic storage duration might lead to unexpected behavior.
82 * @note If the exit function stored in an `exit_action` object refers to a local variable of the function where it is
83 * defined (e.g., as a lambda capturing the variable by reference), and that variable is used as a return operand in
84 * that function, that variable might have already been returned when the `exit_action`'s destructor executes, calling
85 * the exit function. This can lead to surprising behavior.
86 */
87template<typename ExitFunc>
88class [[nodiscard("The object must be used to ensure the exit function is called on scope exit.")]] exit_action {
89public:
90 /**
91 * @brief Constructs a new @a exit_action from an exit function of type @a Func.
92 *
93 * Initializes the exit function with a function or function object `fn`. The constructed `exit_action` is active.
94 * If `Func` is not an lvalue reference type, and `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`, the
95 * stored exit function is initialized with `std::forward<Func>(fn)`; otherwise it is initialized with `fn`. If
96 * initialization of the stored exit function throws an exception, calls `fn()`.
97 *
98 * This overload participates in overload resolution only if:
99 * - `std::is_same_v<std::remove_cvref_t<Func>, exit_action>` is `false`, and
100 * - `std::is_constructible_v<ExitFunc, Func>` is `true`.
101 *
102 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
103 * @param fn Exit function.
104 * @throw anything Any exception thrown during the initialization of the stored exit function.
105 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/scope_exit
106 */
107 template<typename Func>
108 requires(detail::can_construct_from<exit_action, ExitFunc, Func>)
109 explicit exit_action(
110 Func&& fn
111 ) noexcept(std::is_nothrow_constructible_v<ExitFunc, Func> || std::is_nothrow_constructible_v<ExitFunc, Func&>)
112 try
113 : m_exit_function(
114 detail::conditional_forward(
115 std::forward<Func>(fn),
116 std::bool_constant<
117 std::is_nothrow_constructible_v<ExitFunc, Func> && !std::is_lvalue_reference_v<Func>>()
118 )
119 )
120 {}
121 catch (...) {
122 fn();
123 }
124
125 /**
126 * @brief Constructs a new @a exit_action from an exit function of type @a Func.
127 *
128 * Initializes the exit function with a function or function object `fn`. The constructed `exit_action` is active.
129 * The stored exit function is initialized with `std::forward<Func>(fn)`.
130 *
131 * This overload participates in overload resolution only if:
132 * - `std::is_same_v<std::remove_cvref_t<Func>, exit_action>` is `false`, and
133 * - `std::is_lvalue_reference_v<Func>` is `false`, and
134 * - `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`.
135 *
136 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
137 * @param fn Exit function.
138 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/scope_exit
139 */
140 template<typename Func>
141 requires(detail::can_move_construct_from_noexcept<exit_action, ExitFunc, Func>)
142 explicit exit_action(Func&& fn) noexcept : m_exit_function(std::forward<Func>(fn))
143 {}
144
145 /**
146 * @brief Move constructor.
147 *
148 * Initializes the stored exit function with the one in `other`. The constructed `exit_action` is active
149 * if and only if `other` is active before the construction.
150 *
151 * If `std::is_nothrow_move_constructible_v<ExitFunc>` is true, initializes stored exit function (denoted by
152 * `exitfun`) with `std::forward<ExitFunc>(other.exitfun)`, otherwise initializes it with `other.exitfun`.
153 *
154 * After successful move construction, `other` becomes inactive.
155 *
156 * This overload participates in overload resolution only if:
157 * - `std::is_nothrow_move_constructible_v<ExitFunc>` is `true`, or
158 * - `std::is_copy_constructible_v<ExitFunc>` is `true`.
159 *
160 * @param other `exit_action` to move from.
161 * @throw anything Any exception thrown during the initialization of the stored exit function.
162 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/scope_exit
163 */
165 exit_action&& other
166 ) noexcept(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_nothrow_copy_constructible_v<ExitFunc>)
167 requires(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_copy_constructible_v<ExitFunc>)
168 : m_exit_function(
169 detail::conditional_forward(
170 std::forward<ExitFunc>(other.m_exit_function),
171 std::bool_constant<std::is_nothrow_move_constructible_v<ExitFunc>>()
172 )
173 ),
174 m_is_armed(other.m_is_armed)
175 {
176 other.release();
177 }
178
179 /** @cond */
180 /** @brief @a exit_action is not @a CopyConstructible */
181 exit_action(const exit_action&) = delete;
182 /** @brief @a exit_action is not @a CopyAssignable */
183 exit_action& operator=(const exit_action&) = delete;
184 /** @brief @a exit_action is not @a MoveAssignable */
185 exit_action& operator=(exit_action&&) = delete;
186 /** @endcond */
187
188 /**
189 * @brief Calls the exit function if @a m_is_armed is active, then destroys the object.
190 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/%7Escope_exit
191 */
192 ~exit_action() noexcept
193 {
194 if (this->m_is_armed) {
195 this->m_exit_function();
196 }
197 }
198
199 /**
200 * @brief Makes the @a exit_action object inactive.
201 *
202 * Once an @a exit_action is inactive, it cannot become active again, and it will not call its exit function upon
203 * destruction.
204 *
205 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/release
206 */
207 void release() noexcept { this->m_is_armed = false; }
208
209private:
210 ExitFunc m_exit_function; ///< The stored exit function.
211 bool m_is_armed = true; ///< Whether this `exit_action` is active.
212};
213
214/**
215 * @brief Deduction guide for @a exit_action.
216 *
217 * @tparam ExitFunc Exit function type.
218 */
219template<typename ExitFunc>
221
222/**
223 * @brief A scope guard that calls its exit function when a scope is exited via an exception.
224 *
225 * Like `exit_action`, a `fail_action` may be active or inactive. A `fail_action` is active after construction from an
226 * exit function.
227 *
228 * An `fail_action` becomes inactive by calling `release()` or a move constructor. An inactive `fail_action`
229 * may also be obtained by initializing with another inactive `fail_action`. Once an `fail_action` is inactive,
230 * it cannot become active again.
231 *
232 * Usage example:
233 * @snippet{trimleft} scope_action.cpp Using fail_action: runs only if an exception occurs
234 *
235 * @tparam ExitFunc Exit function type. Func is either a
236 * [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible)
237 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) type, or an lvalue reference to a
238 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) or function.
239 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail
240 * @note Constructing a `fail_action` of dynamic storage duration might lead to unexpected behavior.
241 * @note Constructing a `fail_action` from another `fail_action` created in a different thread might also lead to
242 * unexpected behavior since the count of uncaught exceptions obtained in different threads may be compared during
243 * the destruction.
244 */
245template<typename ExitFunc>
246class [[nodiscard("The object must be used to ensure the exit function is called due to an exception.")]] fail_action {
247public:
248 /**
249 * @brief Constructs a new @a fail_action from an exit function of type @a Func.
250 *
251 * Initializes the exit function with a function or function object, and initializes
252 * the counter of uncaught exceptions as if with `std::uncaught_exceptions()`.
253 * The constructed `fail_action` is active.
254 *
255 * If `Func` is not an lvalue reference type, and `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`, the
256 * stored exit function is initialized with `std::forward<Func>(fn)`; otherwise it is initialized with `fn`. If
257 * initialization of the stored exit function throws an exception, calls `fn()`.
258 *
259 * This overload participates in overload resolution only if:
260 * - `std::is_same_v<std::remove_cvref_t<Func>, fail_action>` is `false`, and
261 * - `std::is_constructible_v<ExitFunc, Func>` is `true`.
262 *
263 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
264 * @param fn Exit function.
265 * @throw anything Any exception thrown during the initialization of the stored exit function.
266 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail/scope_fail
267 */
268 template<typename Func>
269 requires(detail::can_construct_from<fail_action, ExitFunc, Func>)
270 explicit fail_action(
271 Func&& fn
272 ) noexcept(std::is_nothrow_constructible_v<ExitFunc, Func> || std::is_nothrow_constructible_v<ExitFunc, Func&>)
273 try
274 : m_exit_function(
275 detail::conditional_forward(
276 std::forward<Func>(fn),
277 std::bool_constant<
278 std::is_nothrow_constructible_v<ExitFunc, Func> && !std::is_lvalue_reference_v<Func>>()
279 )
280 )
281 {}
282 catch (...) {
283 fn();
284 }
285
286 /**
287 * @brief Constructs a new @a fail_action from an exit function of type @a Func.
288 *
289 * Initializes the exit function with a function or function object `fn`. The constructed `fail_action` is active.
290 * The stored exit function is initialized with `std::forward<Func>(fn)`.
291 *
292 * This overload participates in overload resolution only if:
293 * - `std::is_same_v<std::remove_cvref_t<Func>, fail_action>` is `false`, and
294 * - `std::is_lvalue_reference_v<Func>` is `false`, and
295 * - `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`.
296 *
297 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
298 * @param fn Exit function.
299 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail/scope_fail
300 */
301 template<typename Func>
302 requires(detail::can_move_construct_from_noexcept<fail_action, ExitFunc, Func>)
303 explicit fail_action(Func&& fn) noexcept : m_exit_function(std::forward<Func>(fn))
304 {}
305
306 /**
307 * @brief Move constructor.
308 *
309 * Initializes the stored exit function with the one in `other`, and initializes the counter of
310 * uncaught exceptions with the one in `other`. The constructed `fail_action` is active
311 * if and only if `other` is active before the construction.
312 *
313 * If `std::is_nothrow_move_constructible_v<ExitFunc>` is true, initializes stored exit function (denoted by
314 * `exitfun`) with `std::forward<ExitFunc>(other.exitfun)`, otherwise initializes it with `other.exitfun`.
315 *
316 * After successful move construction, `other.release()` is called and `other` becomes inactive.
317 *
318 * This overload participates in overload resolution only if:
319 * - `std::is_nothrow_move_constructible_v<ExitFunc>` is `true`, or
320 * - `std::is_copy_constructible_v<ExitFunc>` is `true`.
321 *
322 * @param other `fail_action` to move from.
323 * @throw anything Any exception thrown during the initialization of the stored exit function.
324 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail/scope_fail
325 */
327 fail_action&& other
328 ) noexcept(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_nothrow_copy_constructible_v<ExitFunc>)
329 requires(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_copy_constructible_v<ExitFunc>)
330 : m_exit_function(
331 detail::conditional_forward(
332 std::forward<ExitFunc>(other.m_exit_function),
333 std::bool_constant<std::is_nothrow_move_constructible_v<ExitFunc>>()
334 )
335 ),
336 m_uncaught_exceptions_count(other.m_uncaught_exceptions_count)
337 {
338 other.release();
339 }
340
341 /** @cond */
342 /** @brief @a fail_action is not @a CopyConstructible */
343 fail_action(const fail_action&) = delete;
344 /** @brief @a fail_action is not @a CopyAssignable */
345 fail_action& operator=(const fail_action&) = delete;
346 /** @brief @a fail_action is not @a MoveAssignable */
347 fail_action& operator=(fail_action&&) = delete;
348 /** @endcond */
349
350 /**
351 * @brief Calls the exit function if the scope is exited via an exception and destroys the object.
352 *
353 * Calls the exit function if the result of `std::uncaught_exceptions()` is greater than the counter of uncaught
354 * exceptions (typically on stack unwinding) and the `fail_action` is active; then destroys the object.
355 *
356 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail/%7Escope_fail
357 */
358 ~fail_action() noexcept
359 {
360 if (std::uncaught_exceptions() > this->m_uncaught_exceptions_count) {
361 this->m_exit_function();
362 }
363 }
364
365 /**
366 * @brief Makes the @a fail_action object inactive.
367 *
368 * Once an @a fail_action is inactive, it cannot become active again, and it will not call its exit function upon
369 * destruction.
370 *
371 * @note @a release() may be either manually called or automatically called by `fail_action`'s move constructor.
372 * @see https://en.cppreference.com/w/cpp/experimental/scope_fail/release
373 */
374 void release() noexcept { this->m_uncaught_exceptions_count = std::numeric_limits<int>::max(); }
375
376private:
377 ExitFunc m_exit_function; ///< The stored exit function.
378 int m_uncaught_exceptions_count = std::uncaught_exceptions(); ///< The counter of uncaught exceptions.
379};
380
381/**
382 * @brief Deduction guide for @a fail_action.
383 *
384 * @tparam ExitFunc Exit function type.
385 */
386template<typename ExitFunc>
388
389/**
390 * @brief A scope guard that calls its exit function when a scope is exited normally.
391 *
392 * Like `exit_action`, a `success_action` may be active or inactive. A `success_action` is active after construction
393 * from an exit function.
394 *
395 * An `success_action` becomes inactive by calling `release()` or a move constructor. An inactive `success_action`
396 * may also be obtained by initializing with another inactive `success_action`. Once an `success_action` is inactive,
397 * it cannot become active again.
398 *
399 * Usage example:
400 * @snippet{trimleft} scope_action.cpp Using success_action: runs only if no exception occurs
401 *
402 * @tparam ExitFunc Exit function type. Func is either a
403 * [Destructible](https://en.cppreference.com/w/cpp/named_req/Destructible)
404 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) type, or an lvalue reference to a
405 * [FunctionObject](https://en.cppreference.com/w/cpp/named_req/FunctionObject) or function.
406 * @see https://en.cppreference.com/w/cpp/experimental/scope_success
407 * @note Constructing a `success_action` of dynamic storage duration might lead to unexpected behavior.
408 * @note Constructing a `success_action` from another `success_action` created in a different thread might also lead to
409 * unexpected behavior since the count of uncaught exceptions obtained in different threads may be compared during
410 * the destruction.
411 * @note If the exit function stored in an `success_action` object refers to a local variable of the function where it
412 * is defined (e.g., as a lambda capturing the variable by reference), and that variable is used as a return operand in
413 * that function, that variable might have already been returned when the `success_action`'s destructor executes,
414 * calling the exit function. This can lead to surprising behavior.
415 */
416template<typename ExitFunc>
417class [[nodiscard(
418 "The object must be used to ensure the exit function is called on a clean scope exit."
419)]] success_action {
420public:
421 /**
422 * @brief Constructs a new @a success_action from an exit function of type @a Func.
423 *
424 * Initializes the exit function with a function or function object, and initializes
425 * the counter of uncaught exceptions as if with `std::uncaught_exceptions()`.
426 * The constructed `success_action` is active.
427 *
428 * If `Func` is not an lvalue reference type, and `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`, the
429 * stored exit function is initialized with `std::forward<Func>(fn)`; otherwise it is initialized with `fn`. If
430 * initialization of the stored exit function throws an exception, calls `fn()`.
431 *
432 * This overload participates in overload resolution only if:
433 * - `std::is_same_v<std::remove_cvref_t<Func>, success_action>` is `false`, and
434 * - `std::is_constructible_v<ExitFunc, Func>` is `true`.
435 *
436 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
437 * @param fn Exit function.
438 * @throw anything Any exception thrown during the initialization of the stored exit function.
439 * @see https://en.cppreference.com/w/cpp/experimental/scope_success/scope_success
440 */
441 template<typename Func>
442 requires(detail::can_construct_from<success_action, ExitFunc, Func>)
444 Func&& fn
445 ) noexcept(std::is_nothrow_constructible_v<ExitFunc, Func> || std::is_nothrow_constructible_v<ExitFunc, Func&>)
446 : m_exit_function(
447 detail::conditional_forward(
448 std::forward<Func>(fn),
449 std::bool_constant<
450 std::is_nothrow_constructible_v<ExitFunc, Func> && !std::is_lvalue_reference_v<Func>>()
451 )
452 )
453 {}
454
455 /**
456 * @brief Constructs a new @a success_action from an exit function of type @a Func.
457 *
458 * Initializes the exit function with a function or function object `fn`. The constructed `success_action` is
459 * active. The stored exit function is initialized with `std::forward<Func>(fn)`.
460 *
461 * This overload participates in overload resolution only if:
462 * - `std::is_same_v<std::remove_cvref_t<Func>, success_action>` is `false`, and
463 * - `std::is_lvalue_reference_v<Func>` is `false`, and
464 * - `std::is_nothrow_constructible_v<ExitFunc, Func>` is `true`.
465 *
466 * @tparam Func Exit function type. Must be constructible from @a ExitFunc.
467 * @param fn Exit function.
468 * @see https://en.cppreference.com/w/cpp/experimental/scope_success/scope_success
469 */
470 template<typename Func>
471 requires detail::can_move_construct_from_noexcept<success_action, ExitFunc, Func>
472 explicit success_action(Func&& fn) noexcept : m_exit_function(std::forward<Func>(fn))
473 {}
474
475 /**
476 * @brief Move constructor.
477 *
478 * Initializes the stored exit function with the one in `other`, and initializes the counter of
479 * uncaught exceptions with the one in `other`. The constructed `success_action` is active
480 * if and only if `other` is active before the construction.
481 *
482 * If `std::is_nothrow_move_constructible_v<ExitFunc>` is true, initializes stored exit function (denoted by
483 * `exitfun`) with `std::forward<ExitFunc>(other.exitfun)`, otherwise initializes it with `other.exitfun`.
484 *
485 * After successful move construction, `other.release()` is called and `other` becomes inactive.
486 *
487 * This overload participates in overload resolution only if:
488 * - `std::is_nothrow_move_constructible_v<ExitFunc>` is `true`, or
489 * - `std::is_copy_constructible_v<ExitFunc>` is `true`.
490 *
491 * @param other `success_action` to move from.
492 * @throw anything Any exception thrown during the initialization of the stored exit function.
493 * @see https://en.cppreference.com/w/cpp/experimental/scope_success/scope_success
494 */
496 success_action&& other
497 ) noexcept(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_nothrow_copy_constructible_v<ExitFunc>)
498 requires(std::is_nothrow_move_constructible_v<ExitFunc> || std::is_copy_constructible_v<ExitFunc>)
499 : m_exit_function(
500 detail::conditional_forward(
501 std::forward<ExitFunc>(other.m_exit_function),
502 std::bool_constant<std::is_nothrow_move_constructible_v<ExitFunc>>()
503 )
504 ),
505 m_uncaught_exceptions_count(other.m_uncaught_exceptions_count)
506 {
507 other.release();
508 }
509
510 /** @cond */
511 /** @brief @a success_action is not @a CopyConstructible */
512 success_action(const success_action&) = delete;
513 /** @brief @a success_action is not @a CopyAssignable */
514 success_action& operator=(const success_action&) = delete;
515 /** @brief @a success_action is not @a MoveAssignable */
516 success_action& operator=(success_action&&) = delete;
517 /** @endcond */
518
519 /**
520 * @brief Calls the exit function when the scope is exited normally if the `success_action` is active, then destroys
521 * the object.
522 *
523 * Calls the exit function if the result of `std::uncaught_exceptions()` is less than or equal
524 * to the counter of uncaught exceptions (typically on normal exit) and the `success_action` is active,
525 * then destroys the object.
526 *
527 * @throws anything Throws any exception thrown by calling the exit function.
528 * @see https://en.cppreference.com/w/cpp/experimental/scope_success/%7Escope_success
529 */
530 ~success_action() noexcept(noexcept(this->m_exit_function()))
531 {
532 if (std::uncaught_exceptions() <= this->m_uncaught_exceptions_count) {
533 this->m_exit_function();
534 }
535 }
536
537 /**
538 * @brief Makes the @a success_action object inactive.
539 *
540 * Once an @a success_action is inactive, it cannot become active again, and it will not call its exit function upon
541 * destruction.
542 *
543 * @see https://en.cppreference.com/w/cpp/experimental/scope_exit/release
544 */
545 void release() noexcept { this->m_uncaught_exceptions_count = std::numeric_limits<int>::min(); }
546
547private:
548 ExitFunc m_exit_function; ///< The stored exit function.
549 int m_uncaught_exceptions_count = std::uncaught_exceptions(); ///< The counter of uncaught exceptions.
550};
551
552/**
553 * @brief Deduction guide for @a success_action.
554 *
555 * @tparam ExitFunc Exit function type.
556 */
557template<typename ExitFunc>
559
560/**
561 * @example scope_action.cpp
562 * Example of using `exit_action`, `fail_action`, and `success_action`.
563 */
564
565} // namespace wwa::utils
566
567#endif /* A2100C2E_3B3D_4875_ACA4_BFEF2E5B6120 */
A scope guard that calls its exit function on destruction, when a scope is exited.
exit_action(Func &&fn) noexcept
Constructs a new exit_action from an exit function of type Func.
exit_action(exit_action &&other) noexcept(std::is_nothrow_move_constructible_v< ExitFunc >||std::is_nothrow_copy_constructible_v< ExitFunc >)
Move constructor.
exit_action(Func &&fn) noexcept(std::is_nothrow_constructible_v< ExitFunc, Func >||std::is_nothrow_constructible_v< ExitFunc, Func & >)
Constructs a new exit_action from an exit function of type Func.
~exit_action() noexcept
Calls the exit function if m_is_armed is active, then destroys the object.
void release() noexcept
Makes the exit_action object inactive.
A scope guard that calls its exit function when a scope is exited via an exception.
fail_action(fail_action &&other) noexcept(std::is_nothrow_move_constructible_v< ExitFunc >||std::is_nothrow_copy_constructible_v< ExitFunc >)
Move constructor.
fail_action(Func &&fn) noexcept(std::is_nothrow_constructible_v< ExitFunc, Func >||std::is_nothrow_constructible_v< ExitFunc, Func & >)
Constructs a new fail_action from an exit function of type Func.
void release() noexcept
Makes the fail_action object inactive.
fail_action(Func &&fn) noexcept
Constructs a new fail_action from an exit function of type Func.
~fail_action() noexcept
Calls the exit function if the scope is exited via an exception and destroys the object.
A scope guard that calls its exit function when a scope is exited normally.
success_action(Func &&fn) noexcept(std::is_nothrow_constructible_v< ExitFunc, Func >||std::is_nothrow_constructible_v< ExitFunc, Func & >)
Constructs a new success_action from an exit function of type Func.
~success_action() noexcept(noexcept(this->m_exit_function()))
Calls the exit function when the scope is exited normally if the success_action is active,...
success_action(success_action &&other) noexcept(std::is_nothrow_move_constructible_v< ExitFunc >||std::is_nothrow_copy_constructible_v< ExitFunc >)
Move constructor.
void release() noexcept
Makes the success_action object inactive.
success_action(Func &&fn) noexcept
Constructs a new success_action from an exit function of type Func.
Library namespace.
success_action(ExitFunc) -> success_action< ExitFunc >
Deduction guide for success_action.
exit_action(ExitFunc) -> exit_action< ExitFunc >
Deduction guide for exit_action.
fail_action(ExitFunc) -> fail_action< ExitFunc >
Deduction guide for fail_action.