C++ Logo

std-discussion

Advanced search

Re: Fwd: Some feedback on scope guards

From: Lénárd Szolnoki <cpp_at_[hidden]>
Date: Sun, 16 Apr 2023 19:41:11 +0100
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.

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

>
> And regarding storage, here's another use case that makes use of a
> scope
> guard as a non-automatic object - program exit handlers.
>
> // At namespace scope
> scope_exit at_exit_guard([] { puts("Good bye cruel world!"); });
>
> Or make that thread_local to make it a thread exit handler.
>
> Yes, around 97.5% of use cases will be complete objects on the stack
> with no moves and no (de)activates, but that doesn't mean the scope
> guard is inherently a non-moveable always-complete object on the
> stack.
> No, a scope guard is a class that calls arbitrary function from its
> destructor, period. Nowhere in this definition is there anything
> about
> its storage or composability, and I don't see why there should be.
>
> This whole idea of limiting scope guards to just complete objects on
> the
> stack only appeared as a workaround for incompatibility with
> coroutines,
> and to that I say I don't like this tradeoff, not at all. Again, if
> you
> want to limit scope guards to just stack-based use (I don't; I find
> it
> useful to be able to use scope guards in other contexts, like above)
> then just stop using classes and destructors for this purpose. This
> is
> no longer a tool for describing and creating objects, this is a tool
> for
> describing control flow, so you should define it accordingly. You
> will
> sidestep the uncaught_exceptions() issue elegantly, and introduce
> nice
> features like anonymous scope guards in the process. And no,
> try/catch
> doesn't cut it as a replacement.
>
> Actually, I would not be opposed to having both the native core
> language
> scope guards and the scope guard types, for different use cases.
>

Received on 2023-04-16 18:41:16