Le 2023-12-05 16:54, Andrey Semashev via Boost a écrit :
On 12/5/23 17:34, Julien Blanc via Boost wrote:
Regarding why scope_fail doesn't enforce noexcept-ness of the action, it is because the "failure" may be indicated by other means than an exception. The library explicitly supports error codes as an alternative.
In general, I think that marking scope guards' destructors noexcept is pointless. If the action throws while there is another exception in flight, your program will terminate either way. If the action throws while there is no other exception then why should the scope guard terminate the program? Throwing in this case might as well be the intended behavior. Because if it isn't intended then it is the user who must communicate this by marking his operator() as noexcept.
I think there's a misunderstanding here. My point was exactly about asserting is_nothrow_invocable for the scope_fail constructor argument, not for its destructor.
scope_success / scope_fail are not default-constructible, although they have a valid empty state.
No, they don't. There is an inactive state, but that state is not "empty", as the function objects in the scope guard remain constructed regardless of the active/inactive state. In particular, any resources that may be owned by the function objects remain allocated until the scope guard is destroyed.
They indeed have two inactive states: * the released() state * the moved-from state Default construction would be similar to a moved-from state.
I think, there is a misunderstanding as to what would be the result of default-constructing a scope guard.
If default construction is to be supported for scope guards, it would definitely require both function objects specified in the scope guard template parameters to be default-constructible as well. Actually, the condition function would have to be nothrow-default-constructible even. So default-constructing a scope guard would also default-construct the function objects, and those function objects *must be callable* in that state.
That's not exact. the default condition function is always_true, and it is nothrow-default-constructible. So it all boils down to the function the user provide. By default creating to the inactive state, you don't need it to be invocable in its default-constructed state. But i found the root of the misunderstanding: there's no move operator in scope_exit. We have one in our scope guard, I incorrectly assumed it was also present. Without it, default construction does indeed not lead to something very useful.
I have presented examples for delayed activation of the scope guard in the docs. It is indispensable if your scope guard needs to be created (and, consequently, destroyed) at a higher-level scope than where you decide whether it needs to be activated. That it is missing in the TS is one of my biggest complaints about it.
Ok, granted. In our code base, this is exactly why we have a move assignment operator for scope_guard. I find this solution more elegant, but it requires you to have a type-erased trivially copyable functor. [unique_resource]
I'd like to note that the way resource traits are currently defined, they allow multiple unallocated states of the resource. For example, for POSIX file descriptors, any negative value is unallocated while -1 is just the default. As far as I understand, `markable` doesn't support this.
It does, and in a way that is very similar to unique_resource: https://github.com/akrzemi1/markable/blob/master/documentation/overview.adoc...
From the implementation standpoint, I don't think that relying on `markable` for detecting unallocated state would simplify the code much, if at all. You'd still have to effectively duplicate the implementation of unique_resource.
A very basic implementation of unique_resource could ressemble this:
template