C++ Logo

std-discussion

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
types.

> 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