C++ Logo


Advanced search

Re: Fwd: Some feedback on scope guards

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Sun, 16 Apr 2023 21:45:32 +0300
On 4/16/23 21:41, Lénárd Szolnoki via Std-Discussion wrote:
> On Sun, 2023-04-16 at 21:36 +0300, Andrey Semashev via Std-Discussion
> wrote:
>> On 4/16/23 19:38, Jason McKesson via Std-Discussion wrote:
>>> On Sun, Apr 16, 2023 at 11:36 AM Andrey Semashev
>>> <andrey.semashev_at_[hidden]> wrote:
>>>> On April 16, 2023 5:29:27 PM Jason McKesson via Std-Discussion
>>>> <std-discussion_at_[hidden]> wrote:
>>>>> It'd be great if we had some kind of attribute that would make
>>>>> it a
>>>>> warning to use such a type in a non-block scoped way, or
>>>>> outside of
>>>>> other block-scoped types. But otherwise, the concept is valid.
>>>>> And so
>>>>> long as that concept is valid, there is no reason to a priori
>>>>> forbid
>>>>> their use as members of other block-scoped types.
>>>> No, the concept doesn't look valid to me.
>>> I think we may have mixed up the "concept" in question. The
>>> attribute
>>> thing was just an off-the-cuff suggestion. "The concept" was the
>>> validity of having block-scoped types being a member of another
>>> object
>>> which itself is block-scoped.
>>>> What about having a block-scoped
>>>> unique_ptr pointing to such type? Presumably, unique_ptr won't be
>>>> marked as
>>>> block-scoped, so should this be forbidden?
>>> "Forbidden" is a strong word, but should it be discouraged? Yes.
>>> Let's break this down. What we have is a type that is, by design,
>>> intended to be used in a statically block-scoped way. The type is
>>> non-moveable, so users cannot transfer ownership from its
>>> originating
>>> named object (prvalues allow them to escape a function call, but at
>>> some point, it gets a name and cannot be moved from there). This is
>>> a
>>> conceptual invariant: once they get a name, their destructor is
>>> statically bound to the C++ language scope of that name (outside of
>>> doing oddball things like directly calling the destructor).
>> 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;
>> }
> Well, you have scope guards, so why not write this?
> auto start_transaction(transaction_data& tr)
> {
> scope_success init_tr([&] {tr.init_with_data_data(x, y, z);});
> return scope_exit([&] { tr.complete(); });
> }
> No need for `scope_exit` to be movable here.

The type needs to be formally moveable, even if the move constructor is
elided, is it not?

Anyway, regardless of the example, scope guards are defined as moveable

> BTW, movable or not, `scope_fail` and `scope_success` are broken if you
> return them from a catch block.

No, because uncaught_exceptions() is already decremented in a catch block.

Received on 2023-04-16 18:45:46