C++ Logo

std-discussion

Advanced search

Re: Some feedback on scope guards

From: Edward Catmur <ecatmur_at_[hidden]>
Date: Fri, 7 Apr 2023 23:31:22 -0500
On Fri, 7 Apr 2023 at 22:45, Edward Catmur <ecatmur_at_[hidden]> wrote:

>
>
> On Fri, 7 Apr 2023 at 18:54, Andrey Semashev via Std-Discussion <
> std-discussion_at_[hidden]> wrote:
>
>> On 4/8/23 01:49, Thiago Macieira via Std-Discussion wrote:
>> > On Friday, 7 April 2023 14:31:46 -03 Andrey Semashev via Std-Discussion
>> wrote:
>> >> 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:
>> >
>> > The standard solution does not need your suggested implementation
>> details. It
>> > just needs to describe the expected behaviour and require that the
>> > implementations do it properly. They may have other means of achieving
>> the
>> > same result.
>>
>> Sure, the standard may simply require a certain behavior, and I did not
>> intend my proposed solution to be adopted or even be part of the
>> standard wording. I simply indicated that there is a way to achieve
>> this, which is something that is welcome for any proposal, isn't it?
>>
>> The point is, the current TS wording explicitly mentions
>> unhandled_exceptions(), and it should not. Instead, it should describe
>> the required behavior, including when used in conjunction with
>> coroutines. Though I would still prefer if the behavior was
>> implementable using the standard library API so that non-standard scope
>> guard libraries like Boost.Scope could be implemented without resorting
>> to compiler-specific intrinsics or private APIs.
>
>
> Your putative co_unhandled_exceptions() sounds like it would have pretty
> substantial overhead - an extra word-sized counter per coroutine, and the
> overhead of updating it whenever you resume a coroutine. It's a big ask
> compared to the plain unhandled_exceptions(), which is one word per thread
> and only updated when exceptions are thrown/caught, so lost in the noise.
>
> I think it's a lot more likely that compilers will just create types whose
> destructors are marked as being called only either from scope exit or from
> unwind cleanup, and omitted in the other case. (At least, that's how I'd
> implement it.) So Boost.Scope etc. will need to either use those magic
> library types, or the attributes/intrinsics those library types use (if
> they aren't implemented with True Name magic).
>

Actually, gcc lets you do something approximating this today, with a bit of
hacking. (clang is stricter, but there still might be something possible.):

#include <stdio.h>
struct guard {
    bool& p;
    ~guard() { p = true; }
};
struct scope {
    bool b = false;
    ~scope() { puts(b ? "exited via exception" : "exited normally"); }
};
static void f(bool p) {
    scope s;
    goto l;
k: return;
l: guard g{s.b};
    if (p)
        throw 1;
    asm goto("jmp %l[k]"::::k);
    __builtin_unreachable();
}
int main(int argc, char* argv[]) {
    try { f(argc > 1); } catch(...) { return 1; }
}

https://godbolt.org/z/af7K8nG1x

This kind of thing makes such cleaner code than comparing exception counts,
even without considering coroutines, that I'd be very surprised if Library
didn't end up asking their compiler writers for something like it.

I agree with Thiago that it's more important to establish what the correct
> behavior is around coroutines, so we can get it into wording as examples
> and as the basis of Library tests.
>

Received on 2023-04-08 04:31:36