From 897877fd82b836e8b22b6b95a9421d3f77fed856 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 23 Jun 2025 10:40:12 +0100 Subject: [PATCH] P3503R3 Make type-erased allocator use in promise and packaged_task consistent In p4 and p5 there were merge conflicts with LWG 4154 but easily resolved. --- source/threads.tex | 63 ++++++++++++++++++++++++++++------------------ 1 file changed, 38 insertions(+), 25 deletions(-) diff --git a/source/threads.tex b/source/threads.tex index 1b3e2577fb..c287f47c00 100644 --- a/source/threads.tex +++ b/source/threads.tex @@ -10724,9 +10724,6 @@ void set_value_at_thread_exit(@\seebelow@); void set_exception_at_thread_exit(exception_ptr p); }; - - template - struct uses_allocator, Alloc>; } \end{codeblock} @@ -10746,20 +10743,6 @@ they acquire a single mutex associated with the promise object while updating the promise object. -\indexlibrarymember{uses_allocator}{promise}% -\begin{itemdecl} -template - struct uses_allocator, Alloc> - : true_type { }; -\end{itemdecl} - -\begin{itemdescr} -\pnum -\expects -\tcode{Alloc} meets -the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. -\end{itemdescr} - \indexlibraryctor{promise}% \begin{itemdecl} promise(); @@ -11861,6 +11844,8 @@ packaged_task() noexcept; template explicit packaged_task(F&& f); + template + explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); ~packaged_task(); // no copy @@ -11910,6 +11895,19 @@ explicit packaged_task(F&& f); \end{itemdecl} +\begin{itemdescr} +\pnum +\effects +Equivalent to +\tcode{packaged_task(allocator_arg, allocator(), std::forward(f))}. +\end{itemdescr} + +\indexlibraryctor{packaged_task}% +\begin{itemdecl} +template + explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); +\end{itemdecl} + \begin{itemdescr} \pnum \constraints @@ -11920,17 +11918,27 @@ \mandates \tcode{is_invocable_r_v\&, ArgTypes...>} is \tcode{true}. +\pnum +\expects +\tcode{Allocator} meets the \oldconcept{Allocator} requirements\iref{allocator.requirements.general}. + \pnum \effects +Let \tcode{A2} be +\tcode{allocator_traits::rebind_alloc<\unspec>} +and let \tcode{a2} be an object of type \tcode{A2} initialized with +\tcode{A2(a)}. Constructs a new \tcode{packaged_task} object with a stored task of type \tcode{decay_t} and a shared state. Initializes the object's stored task with \tcode{std::forward(f)}. +Uses \tcode{a2} to allocate storage for the shared state and stores a copy +of \tcode{a2} in the shared state. \pnum \throws -Any exceptions thrown by the copy or move constructor of \tcode{f}, or -\tcode{bad_alloc} if memory for the internal data structures -cannot be allocated. +Any exceptions thrown by the initialization of the stored task. +If storage for the shared state cannot be allocated, any exception thrown by +\tcode{A2::allocate}. \end{itemdescr} \indexlibraryctor{packaged_task}% @@ -12140,9 +12148,16 @@ \begin{itemdescr} \pnum \effects -As if \tcode{*this = packaged_task(std::move(f))}, where +Equivalent to: +\begin{codeblock} +if (!valid()) + throw future_error(future_errc::no_state); +*this = packaged_task(allocator_arg, a, std::move(f)); +\end{codeblock} +where \tcode{f} is the task stored in -\tcode{*this}. +\tcode{*this} +and \tcode{a} is the allocator stored in the shared state. \begin{note} This constructs a new shared state for \tcode{*this}. The old state is abandoned\iref{futures.state}. @@ -12151,9 +12166,7 @@ \pnum \throws \begin{itemize} -\item \tcode{bad_alloc} if memory for the new shared state cannot be allocated. -\item Any exception thrown by the move constructor of the task stored in the shared -state. +\item Any exception thrown by the \tcode{packaged_task} constructor. \item \tcode{future_error} with an error condition of \tcode{no_state} if \tcode{*this} has no shared state. \end{itemize}