Date: Tue, 2 Jun 2026 07:54:13 +0100
On Mon, 1 Jun 2026, 15:44 Frederick Virchanza Gotham via Std-Proposals, <
std-proposals_at_[hidden]> wrote:
> First I'll introduce the initial motivation behind this feature. The
> function 'std::async' returns an 'std::future' object, and the
> destructor of 'future' blocks until the spawned thread ends. So if you
> had code such as the following:
>
> for ( unsigned i = 0u; i < rows; ++i )
> for ( unsigned j = 0u; j < cols; ++j )
> std::async( EntryPoint );
>
Why are you even using async if you don't want the result it returns?
Just use std::thread(entrypoint).detach();
Or create an array (or a std::vector) to hold the futures in, so the
lifetime is extended to the array.
> Instead of running (rows*cols) threads concurrently, the above code
> snippet will run the threads consecutively, as you can see in the
> following GodBolt:
>
> https://godbolt.org/z/h3Y4f1jGn
>
> You can see in the above GodBolt that the entire program execution
> time is approximately 1 second.
>
> But if we apply the unary operator '%' as follows:
>
> for ( unsigned i = 0u; i < rows; ++i )
> for ( unsigned j = 0u; j < cols; ++j )
> %std::async( EntryPoint );
>
> we can extend the lifetime of any PRvalue until the end of the
> function. The two variables, 'rows' and 'cols', don't even have to be
> compile-time constants, as this new feature uses 'alloca' under the
> hood to allocate space for them on the stack. So now the execution
> time is down to 64 milliseconds:
>
> https://godbolt.org/z/PGqW45nG9
>
> When the function exits, either by a 'return' statement or the
> throwing of an exception, the destructors of function-bound objects
> are executed in the reverse order of their construction. This is
> achieved under the hood by means of traversing a linked list stored on
> the stack (which again was allocated with 'alloca').
>
> So what is this feature good for? Well you can spontaneously lock a
> mutex at any point in a function:
>
> void Func(void)
> {
> if ( a )
> {
> if ( b )
> {
> if ( c )
> {
> %lock_guard{ my_global_mutex };
>
Just use unique_lock initialized with defer_lock at the outer scope, and
lock it whenever desired.
There's no problem that needs to be solved with new features here.
}
> }
> }
>
> DoSomething();
> }
>
> Here is the feature thoroughly torture-tested:
>
> https://godbolt.org/z/aMob4Yndq
>
> And here is the entire compiler patch up on Github:
>
> https://github.com/healytpk/gcc-thomas-healy/commit/tag_classalloca
>
> Personally I think function-bound objects are pretty cool. And you should
> too.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
std-proposals_at_[hidden]> wrote:
> First I'll introduce the initial motivation behind this feature. The
> function 'std::async' returns an 'std::future' object, and the
> destructor of 'future' blocks until the spawned thread ends. So if you
> had code such as the following:
>
> for ( unsigned i = 0u; i < rows; ++i )
> for ( unsigned j = 0u; j < cols; ++j )
> std::async( EntryPoint );
>
Why are you even using async if you don't want the result it returns?
Just use std::thread(entrypoint).detach();
Or create an array (or a std::vector) to hold the futures in, so the
lifetime is extended to the array.
> Instead of running (rows*cols) threads concurrently, the above code
> snippet will run the threads consecutively, as you can see in the
> following GodBolt:
>
> https://godbolt.org/z/h3Y4f1jGn
>
> You can see in the above GodBolt that the entire program execution
> time is approximately 1 second.
>
> But if we apply the unary operator '%' as follows:
>
> for ( unsigned i = 0u; i < rows; ++i )
> for ( unsigned j = 0u; j < cols; ++j )
> %std::async( EntryPoint );
>
> we can extend the lifetime of any PRvalue until the end of the
> function. The two variables, 'rows' and 'cols', don't even have to be
> compile-time constants, as this new feature uses 'alloca' under the
> hood to allocate space for them on the stack. So now the execution
> time is down to 64 milliseconds:
>
> https://godbolt.org/z/PGqW45nG9
>
> When the function exits, either by a 'return' statement or the
> throwing of an exception, the destructors of function-bound objects
> are executed in the reverse order of their construction. This is
> achieved under the hood by means of traversing a linked list stored on
> the stack (which again was allocated with 'alloca').
>
> So what is this feature good for? Well you can spontaneously lock a
> mutex at any point in a function:
>
> void Func(void)
> {
> if ( a )
> {
> if ( b )
> {
> if ( c )
> {
> %lock_guard{ my_global_mutex };
>
Just use unique_lock initialized with defer_lock at the outer scope, and
lock it whenever desired.
There's no problem that needs to be solved with new features here.
}
> }
> }
>
> DoSomething();
> }
>
> Here is the feature thoroughly torture-tested:
>
> https://godbolt.org/z/aMob4Yndq
>
> And here is the entire compiler patch up on Github:
>
> https://github.com/healytpk/gcc-thomas-healy/commit/tag_classalloca
>
> Personally I think function-bound objects are pretty cool. And you should
> too.
> --
> Std-Proposals mailing list
> Std-Proposals_at_[hidden]
> https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals
>
Received on 2026-06-02 06:54:34
