C++ Logo

std-discussion

Advanced search

Re: Some feedback on scope guards

From: Andrey Semashev <andrey.semashev_at_[hidden]>
Date: Mon, 17 Apr 2023 14:44:23 +0300
On 4/17/23 14:36, Andrey Semashev wrote:
> On 4/17/23 14:11, Marcin Jaczewski via Std-Discussion wrote:
>> pon., 17 kwi 2023 o 12:54 Andrey Semashev via Std-Discussion
>> <std-discussion_at_[hidden]> napisał(a):
>>>
>>> On 4/17/23 13:47, Marcin Jaczewski wrote:
>>>> pon., 17 kwi 2023 o 12:35 Andrey Semashev via Std-Discussion
>>>> <std-discussion_at_[hidden]> napisał(a):
>>>>>
>>>>> On 4/17/23 13:27, Marcin Jaczewski via Std-Discussion wrote:
>>>>>>
>>>>>> Why are multiple destructors bad? Especially if they were handled like
>>>>>> `const` overloads.
>>>>>> Besides, if a new destructor is no-go, why not add a new operator that
>>>>>> simply is called before the destructor?
>>>>>> like `operator unwind()` that is called before a proper destructor is
>>>>>> used in case of unwind.
>>>>>
>>>>> It doesn't matter how you name it. If it doesn't work through other
>>>>> types (e.g. if the scope guard is a member or accessed through a
>>>>> pointer) then we have a problem with composability. If it does work,
>>>>> then we're back to the status quo, since the operator will be called
>>>>> under the same conditions as the destructor, and therefore it will need
>>>>> to check for uncaught_exceptions().
>>>>>
>>>>
>>>> `operator unwind() = default;`?
>>>
>>> And what would this mean? That it forwards or that it doesn't?
>>> Regardless of how you answer, my previous reply applies.
>>>
>>
>> Apply same operator to all members.
>>
>>>> And if it's not a direct member then we have the same problem with
>>>> composible as "copy",
>>>> that I suppose is solved problem?
>>>
>>> I'm not sure what you mean here. Default copy constructors/assignments
>>> do forward, but there's no problem with that, so I don't see the relation.
>>>
>>
>> As the same logic applies in both cases, `T(const T&) = default` apply
>> copy for each member.
>> `operator throw_unwind() = default;` is equal to:
>> ```
>> x.operator throw_unwind();
>> y.operator throw_unwind();
>> z.operator throw_unwind();
>> ```
>> Of course if `x` is a pointer then this operator is noop. But we can
>> easy work around this by composition like:
>> ```
>> struct mixing_unwind_deref
>> {
>> template<typename T>
>> operator throw_unwind(this T& self) { if (self) (*self).operator
>> throw_unwind(); }
>> };
>>
>> struct MyPointer : std::unique_ptr<scope_gaurd>, mixing_unwind_deref
>> {
>>
>> };
>> ```
>
> This means every smart pointer and container and any other user-defined
> type that uses pointers as members would have to be updated for this to
> work. This is a big ask.

Also, I wonder how things like shared_ptr and unique_ptr<T[]> would work
with this.

>>>> You miss an important thing `unwind` will be called only when an
>>>> exception unwind code.
>>>
>>> This doesn't help if you still need to check for uncaught_exceptions().
>>>
>>
>> But what would be the point for checking this? even more when its have
>> wrong value
>> when call in coroutine? `uncaught_exceptions` was needed to check if
>> it was throw unwind.
>> This operator gives this info directly. What exactly need I have for
>> this function?
>
> Assuming scope_fail invokes its action from within this `operator
> unwind`, how would nested scope_fails work?
>
>

Received on 2023-04-17 11:44:26