On Sun, 16 Apr 2023 at 18:29, Andrey Semashev via Std-Discussion <std-discussion@lists.isocpp.org> wrote:
On 4/16/23 22:30, Edward Catmur wrote:
>
> On Sun, 16 Apr 2023, 15:36 Andrey Semashev via Std-Discussion,
> <std-discussion@lists.isocpp.org
> <mailto:std-discussion@lists.isocpp.org>> wrote:
>
>     No, scope guards *are* moveable. And I can imagine use cases that rely
>     on them being moveable, like returning an epilogue from a function.
>
>       auto start_transaction(transaction_data& tr)
>       {
>         scope_exit completion_guard([&] { tr.complete(); });
>         tr.init_with_data_data(x, y, z);
>         return completion_guard;
>       }
>
>     And regarding storage, here's another use case that makes use of a scope
>     guard as a non-automatic object - program exit handlers.
>
>       // At namespace scope
>       scope_exit at_exit_guard([] { puts("Good bye cruel world!"); });
>
>     Or make that thread_local to make it a thread exit handler.
>
> Those are both scope_exit, though, not scope_success or scope_failure.
> When would it make sense to return one of the latter two or to use them
> at namespace scope? 

If you define it so that scope_fail is called when main() or a thread
entry function is left with an exception, it could be used for the final
cleanup before program termination. For example, collect a backtrace
before terminating or emit a critical message in the log.

I think uncaught_exceptions() can only be 0 or 1 at that point, though, so you may as well test it directly and not have to worry about the cached value being nonzero?

Returning scope_success/scope_fail from a function makes sense in the
similar cases as shown above, but when you want separate actions on
success or failure (or just one of them).

OK, yes, the commit/rollback use case. At least for returning I don't think you have to worry about the value of uncaught_exceptions() changing.