C++ Logo

std-proposals

Advanced search

Re: [std-proposals] return value lives until end of scope

From: Alejandro Colomar <une+cxx_std-proposals_at_[hidden]>
Date: Sat, 23 May 2026 11:32:19 +0200
Hi,

On 2026-05-23T07:36:52+0000, Frederick Virchanza Gotham via Std-Proposals wrote:
> On Thursday, May 21, 2026, Jonathan Wakely wrote:
>
> >
> >
> > Yeah, I don't want spooky changes to the lifetime model and how it
> > interacts with scopes to happen implicitly based on something far away on
> > the function declaration. If somebody adds __persistent to a declaration,
> > it silently changes the meaning of existing callers. No thanks.
> >
>
>
>
> What if we were to move the 'mark' to the calling site. Perhaps a unary
> operator? So the following:
>
> int main(void)
> {
> %async(Func);
> }
>
> would be the same as:
>
> int main(void)
> {
> auto dummy = async(Func);
> }

What's the point? We already have

 auto _ = async(Func);

Which is objectively better because it tells you what it does. There's
an '=', which tells you that it's being assigned, and thus the usual
rules apply. Are you worried about typing a word as long as 'auto'?
I'd worry more about having yet another meaning for '%' which will
almost certainly confuse programmers.

> Of course this begs the question, what about loops?
>
> for ( unsigned i = 0u; i < N; ++i ) %async(Func);
>
> Well I think in the above line, the scope of the return value should be to
> the nearest preceding {, meaning that after the loop has finished, you have
> N objects on the stack as the N threads run concurrently (implemented by
> the compiler by calling 'alloca' inside the loop with linked list).

That would be very dumb. See the 'defer' proposal for C, which works
with scopes, and thus with blocks. The contents of a for loop are a
secondary block in C (I'm less familiar with C++'s syntax, but whatever
it's called, it should be morally compatible), regardless of whether
there are braces or not. That's the Right Choice.

In fact, we have the same in C++:

 for (int i = 0; i < N; i++)
  auto _ = async(Func);

The scope of _ terminates at each iteration, and thus cleanup is done
after each iteration. If you want % to be equivalent, you should make
it terminate at the same place that an automatic variable would. And if
you don't, you're just creating a massive foot-gun.

> But what if the loop has a curly-braced body?
>
> for ( unsigned i = 0u; i < N, ++i )
> {
> %async(Func);
> Log("new thread started");
> }
>
> In the above code, the return value from 'async' will be destroyed at the
> }, meaning the threads would run consecutively rather than concurrently. If
> you want it to persist up one level, then you double it:
>
> for ( unsigned i = 0u; i < N, ++i )
> {
> %%async(Func);
> Log("new thread started");
> }
>
> And if you want it to persist up another level above that, you triple it:
>
> for ( unsigned i = 0u; i < ROWS; ++i )
> {
> for ( unsigned j = 0u; j < COLS; ++j )
> {
> %%%async(Func);
> Log("new thread started");
> }
> }

Lol. [checks calendar; it's not April 1st; hmmm] No, thanks.


Have a lovely day!
Alex

-- 
<https://www.alejandro-colomar.es>

Received on 2026-05-23 09:32:25