Document: P3980R0
Author: Dietmar Kühl
Date: 2026-02-22
Audience: LEWG
Addresses four NB comments about how std::execution::task uses allocators. The key separation: the allocator for the coroutine frame and the allocator for child sender environments should be handled independently. The frame allocator comes from the task's constructor arguments; the child environment allocator comes from the receiver. Presents three wording approaches (A, B, C) with different levels of strictness on allocator_arg positioning.
Separating frame allocator from child environment allocator is the right design. The frame allocator controls where the coroutine itself lives. The environment allocator controls what the task's children see. These are different concerns with different lifetimes, and conflating them was the source of three of the four NB comments.
This is one of the 29 issues from P3796R1. The task type was adopted and then immediately needed rework. The allocator model is particularly tricky because
operator newin the coroutine frame runs before the promise constructor - the allocator has to be available before the coroutine body starts.The timing problem is exactly what P4003R0 solves with thread-local propagation. Different approach, same underlying constraint: the allocator must be present at invocation time.
Three wording approaches for one NB comment resolution. Option A constrains
allocator_argto first position. Option B allows flexible positioning matchingstd::generator. Option C is a middle ground. This is LEWG design space exploration - they'll poll and pick one.Consistency with
std::generator's allocator model should be the priority. Both are coroutine types. Both need allocators for frame allocation. Users shouldn't learn two different allocator conventions for two standard coroutine types.Four NB comments on allocator use for a single type. This is what happens when you ship a design and discover the allocator story wasn't fully baked. Kühl is doing the cleanup work. Necessary, not glamorous.
Taking the child allocator from the receiver's environment is elegant. The receiver already carries the execution context. Adding the allocator to that context means child tasks automatically inherit the allocation strategy without explicit propagation.
Six months after adoption and we're reworking the allocator model. Between this, P3796R1's 29 issues, and P3801R0's design concerns,
std::execution::taskis getting more post-adoption patches than C++11std::regexgot complaints.