C++ Logo


Advanced search

Re: Some feedback on scope guards

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Fri, 7 Apr 2023 20:41:38 +0300
On 4/7/23 20:31, Andrey Semashev wrote:
> Hi,
> I hope this is the right place to report feedback on C++ Extensions for
> Library Fundamentals TS v3.
> On boost-dev mailing list, there was this discussion that highlighted
> some issues with scope_success/scope_fail scope guards that are defined
> in the Library Fundamentals TS:
> https://lists.boost.org/Archives/boost/2023/04/254418.php
> https://lists.boost.org/Archives/boost/2023/04/254420.php
> (Sorry, the thread got split for some reason.)
> In short, Andrzej Krzemienski points out that using
> unhandled_exceptions() as a way of detecting whether an exception has
> been thrown doesn't work with coroutines because after creating the
> scope guard and capturing the result of unhandled_exceptions() the
> coroutine may be suspended and resumed in a different context where the
> number of unhandled exceptions is different. He then goes on to
> demonstrate the problem with Boost.Scope, an implementation of the scope
> guards proposed for review in Boost.
> I think this issue needs to be addressed in the TS before inclusion into
> the main standard. As a possible solution, I proposed the following idea:
> - When entering a coroutine, capture the current result of
> unhandled_exceptions() in the coroutine state. Let this captured counter
> be accessible via co_unhandled_exceptions().
> - When an exception is thrown or caught within a coroutine, in addition
> to updating the thread-specific uncaught exception counter, the one
> stored in the coroutine state is also similarly updated.
> - When a thrown exception propagates out of a coroutine, and the caller
> is also a coroutine, the parent's unhandled exception counter is updated
> before unwinding the parent stack begins.
> - In scope_success/scope_fail, use co_unhandled_exceptions() instead of
> unhandled_exceptions() to detect if an exception has been thrown.
> I admit this is just a rough idea of what could be done to fix this, and
> it likely needs more thought or may be entirely wrong. This is just food
> for thought.
> Also, unrelated to the above, here are some other comments regarding
> scope guards that I have based on my experience with scope guards (not
> necessarily the ones defined in the TS) and comments I received on
> Boost.Scope:
> 1. I think, there should be a way to activate a deactivated scope guard.
> Also, there should be a way to construct an initially inactive scope
> guard. This is important in cases when the scope guard needs to be
> created earlier (possible in an outer scope) compared to when it should
> become active. Notice that the point of creation of the scope guard
> corresponds to the point when the scope guard action is executed when
> the scope is left, and that point may be different from when it is
> discovered that the scope guard needs to be activated.
> 2. For scope_success/scope_fail, it would be useful to be able to
> specify a user-defined condition function for detecting the failure
> condition. This is useful in cases when the failure is indicated not via
> an exception but via other means, such as returning an error code. The
> idea was implemented in Boost.Scope, where checking for an exception is
> merely a default failure condition, with the user being able to specify
> his own.
> 3. There is room for a scope guard that is more lightweight than
> scope_exit. Specifically, a scope guard that unconditionally calls its
> action, is not moveable and cannot be deactivated. Think of it as
> lock_guard compared to unique_lock. In my experience, the majority of
> scope guards don't need to be able to be (de)activated or moved, so this
> optimization would be useful. Furthermore, such unconditional scope
> guards don't need a name as you won't interact with them after
> construction. Boost.Scope solves the by introducing scope_final guard,
> and a macro to avoid having a name of the scope guard. I realize that
> such a macro is unlikely to get into the standard, but still I would
> like to note that such a feature would be nice. Regardless, a more
> lightweight scope guards such as scope_final would be useful in its own
> right.

4. scope_exit destructor should allow for the action to throw. Since
scope_exit action may be invoked when there is no exception in flight,
the action should be allowed to throw in this case. I see no harm in
this because even if the action throws when there is an exception in
flight, the behavior would be the same as when scope_exit destructor is
marked noexcept - the program will terminate.

> For reference, here is Boost.Scope and its docs:
> https://github.com/lastique/scope
> https://lastique.github.io/scope/libs/scope/doc/html/index.html
> Thanks.

Received on 2023-04-07 17:42:01