%!TEX root = std.tex \rSec0[mem]{Memory management library} \rSec1[mem.general]{General} \pnum This Clause describes components for memory management. \pnum The following subclauses describe general memory management facilities, smart pointers, memory resources, and scoped allocators, as summarized in \tref{mem.summary}. \begin{libsumtab}{Memory management library summary}{mem.summary} \ref{memory} & Memory & \tcode{}, \tcode{} \\ \rowsep \ref{smartptr} & Smart pointers & \tcode{} \\ \rowsep \ref{mem.composite.types} & Types for composite class design & \tcode{} \\ \rowsep \ref{mem.res} & Memory resources & \tcode{} \\ \rowsep \ref{allocator.adaptor} & Scoped allocators & \tcode{} \\ \end{libsumtab} \rSec1[memory]{Memory} \rSec2[memory.general]{General} \pnum Subclause~\ref{memory} describes the contents of the header \libheaderref{memory} and some of the contents of the header \libheaderref{cstdlib}. \rSec2[memory.syn]{Header \tcode{} synopsis} \pnum The header \libheaderdef{memory} defines several types and function templates that describe properties of pointers and pointer-like types, manage memory for containers and other template types, destroy objects, and construct objects in uninitialized memory buffers~(\ref{pointer.traits}--\ref{specialized.addressof} and \ref{specialized.algorithms}). The header also defines the templates \tcode{unique_ptr}, \tcode{shared_ptr}, \tcode{weak_ptr}, \tcode{out_ptr_t}, \tcode{inout_ptr_t}, and various function templates that operate on objects of these types\iref{smartptr}. \pnum Let \tcode{\exposid{POINTER_OF}(T)} denote a type that is \begin{itemize} \item \tcode{T::pointer} if the \grammarterm{qualified-id} \tcode{T::pointer} is valid and denotes a type, \item otherwise, \tcode{T::element_type*} if the \grammarterm{qualified-id} \tcode{T::element_type} is valid and denotes a type, \item otherwise, \tcode{pointer_traits::element_type*}. \end{itemize} \pnum Let \tcode{\exposid{POINTER_OF_OR}(T, U)} denote a type that is: \begin{itemize} \item \tcode{\exposid{POINTER_OF}(T)} if \tcode{\exposid{POINTER_OF}(T)} is valid and denotes a type, \item otherwise, \tcode{U}. \end{itemize} \begin{codeblock} #include // see \ref{compare.syn} namespace std { // \ref{pointer.traits}, pointer traits template struct pointer_traits; // freestanding template struct pointer_traits; // freestanding // \ref{pointer.conversion}, pointer conversion template constexpr T* to_address(T* p) noexcept; // freestanding template constexpr auto to_address(const Ptr& p) noexcept; // freestanding // \ref{ptr.align}, pointer alignment void* align(size_t alignment, size_t size, void*& ptr, size_t& space); // freestanding template constexpr T* assume_aligned(T* ptr); // freestanding template bool is_sufficiently_aligned(T* ptr); // freestanding // \ref{obj.lifetime}, explicit lifetime management template constexpr void start_lifetime(T& r) noexcept; // freestanding template T* start_lifetime_as(void* p) noexcept; // freestanding template const T* start_lifetime_as(const void* p) noexcept; // freestanding template volatile T* start_lifetime_as(volatile void* p) noexcept; // freestanding template const volatile T* start_lifetime_as(const volatile void* p) noexcept; // freestanding template T* start_lifetime_as_array(void* p, size_t n) noexcept; // freestanding template const T* start_lifetime_as_array(const void* p, size_t n) noexcept; // freestanding template volatile T* start_lifetime_as_array(volatile void* p, size_t n) noexcept; // freestanding template const volatile T* start_lifetime_as_array(const volatile void* p, // freestanding size_t n) noexcept; // \ref{allocator.tag}, allocator argument tag struct allocator_arg_t { explicit allocator_arg_t() = default; }; // freestanding inline constexpr allocator_arg_t allocator_arg{}; // freestanding // \ref{allocator.uses}, \tcode{uses_allocator} template struct uses_allocator; // freestanding // \ref{allocator.uses.trait}, \tcode{uses_allocator} template constexpr bool @\libglobal{uses_allocator_v}@ = uses_allocator::value; // freestanding // \ref{allocator.uses.construction}, uses-allocator construction template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding Args&&... args) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; // freestanding template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding U&& u, V&& v) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding pair& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding const pair& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding pair&& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding const pair&& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding P&& p) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, // freestanding U&& u) noexcept; template constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); // freestanding template constexpr T* uninitialized_construct_using_allocator(T* p, // freestanding const Alloc& alloc, Args&&... args); // \ref{allocator.traits}, allocator traits template struct allocator_traits; // freestanding template struct @\libglobal{allocation_result}@ { // freestanding Pointer @\libmember{ptr}{allocation_result}@; SizeType @\libmember{count}{allocation_result}@; }; // \ref{default.allocator}, the default allocator template class allocator; template constexpr bool operator==(const allocator&, const allocator&) noexcept; // \ref{specialized.addressof}, addressof template constexpr T* addressof(T& r) noexcept; // freestanding template const T* addressof(const T&&) = delete; // freestanding // \ref{specialized.algorithms}, specialized algorithms // \ref{special.mem.concepts}, special memory concepts template concept @\exposconcept{nothrow-input-iterator}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-forward-iterator}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-bidirectional-iterator}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-random-access-iterator}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-sentinel-for}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-sized-sentinel-for}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-input-range}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-forward-range}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-bidirectional-range}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-random-access-range}@ = @\seebelow@; // \expos template concept @\exposconcept{nothrow-sized-random-access-range}@ = @\seebelow@; // \expos template constexpr void uninitialized_default_construct(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template void uninitialized_default_construct(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last); template constexpr NoThrowForwardIterator uninitialized_default_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator uninitialized_default_construct_n(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} Size n); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> constexpr I uninitialized_default_construct(I first, S last); // freestanding template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> constexpr borrowed_iterator_t uninitialized_default_construct(R&& r); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> constexpr I uninitialized_default_construct_n(I first, // freestanding iter_difference_t n); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, @\exposconcept{nothrow-sized-sentinel-for}@ S> requires @\libconcept{default_initializable}@> I uninitialized_default_construct(Ep&& exec, I first, S last); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R> requires @\libconcept{default_initializable}@> borrowed_iterator_t uninitialized_default_construct(Ep&& exec, // freestanding-deleted, R&& r); // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I> requires @\libconcept{default_initializable}@> I uninitialized_default_construct_n(Ep&& exec, I first, // freestanding-deleted, iter_difference_t n); // see \ref{algorithms.parallel.overloads} } template constexpr void uninitialized_value_construct(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template void uninitialized_value_construct(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last); template constexpr NoThrowForwardIterator uninitialized_value_construct_n(NoThrowForwardIterator first, Size n); // freestanding template NoThrowForwardIterator uninitialized_value_construct_n(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} Size n); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{default_initializable}@> constexpr I uninitialized_value_construct(I first, S last); // freestanding template<@\exposconcept{nothrow-forward-range}@ R> requires @\libconcept{default_initializable}@> constexpr borrowed_iterator_t uninitialized_value_construct(R&& r); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I> requires @\libconcept{default_initializable}@> constexpr I uninitialized_value_construct_n(I first, // freestanding iter_difference_t n); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, @\exposconcept{nothrow-sized-sentinel-for}@ S> requires @\libconcept{default_initializable}@> I uninitialized_value_construct(Ep&& exec, I first, S last); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R> requires @\libconcept{default_initializable}@> borrowed_iterator_t uninitialized_value_construct(Ep&& exec, // freestanding-deleted, R&& r); // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I> requires @\libconcept{default_initializable}@> I uninitialized_value_construct_n(Ep&& exec, I first, // freestanding-deleted, iter_difference_t n); // see \ref{algorithms.parallel.overloads} } template constexpr NoThrowForwardIterator uninitialized_copy(InputIterator first, // freestanding InputIterator last, NoThrowForwardIterator result); template NoThrowForwardIterator uninitialized_copy(ExecutionPolicy&& exec, // freestanding-deleted, ForwardIterator first, // see \ref{algorithms.parallel.overloads} ForwardIterator last, NoThrowForwardIterator result); template constexpr NoThrowForwardIterator uninitialized_copy_n(InputIterator first, // freestanding Size n, NoThrowForwardIterator result); template NoThrowForwardIterator uninitialized_copy_n(ExecutionPolicy&& exec, // freestanding-deleted, ForwardIterator first, // see \ref{algorithms.parallel.overloads} Size n, NoThrowForwardIterator result); namespace ranges { template using @\libglobal{uninitialized_copy_result}@ = in_out_result; // freestanding template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_reference_t> constexpr uninitialized_copy_result uninitialized_copy(I ifirst, S1 ilast, O ofirst, S2 olast); // freestanding template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_reference_t> constexpr uninitialized_copy_result, borrowed_iterator_t> uninitialized_copy(IR&& in_range, OR&& out_range); // freestanding template using @\libglobal{uninitialized_copy_n_result}@ = in_out_result; // freestanding template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_reference_t> constexpr uninitialized_copy_n_result uninitialized_copy_n(I ifirst, iter_difference_t n, // freestanding O ofirst, S olast); template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ I, @\libconcept{sized_sentinel_for}@ S1, @\exposconcept{nothrow-random-access-iterator}@ O, @\exposconcept{nothrow-sized-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_reference_t> uninitialized_copy_result uninitialized_copy(Ep&& exec, I ifirst, S1 ilast, // freestanding-deleted, O ofirst, S2 olast); // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ IR, @\exposconcept{nothrow-sized-random-access-range}@ OR> requires @\libconcept{constructible_from}@, range_reference_t> uninitialized_copy_result, borrowed_iterator_t> uninitialized_copy(Ep&& exec, IR&& in_range, OR&& out_range); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ I, @\exposconcept{nothrow-random-access-iterator}@ O, @\exposconcept{nothrow-sized-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_reference_t> uninitialized_copy_n_result uninitialized_copy_n(Ep&& exec, I ifirst, iter_difference_t n, // freestanding-deleted, O ofirst, S olast); // see \ref{algorithms.parallel.overloads} } template constexpr NoThrowForwardIterator uninitialized_move(InputIterator first, // freestanding InputIterator last, NoThrowForwardIterator result); template NoThrowForwardIterator uninitialized_move(ExecutionPolicy&& exec, // freestanding-deleted, ForwardIterator first, // see \ref{algorithms.parallel.overloads} ForwardIterator last, NoThrowForwardIterator result); template constexpr pair uninitialized_move_n(InputIterator first, Size n, // freestanding NoThrowForwardIterator result); template pair uninitialized_move_n(ExecutionPolicy&& exec, // freestanding-deleted, ForwardIterator first, Size n, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator result); namespace ranges { template using @\libglobal{uninitialized_move_result}@ = in_out_result; // freestanding template<@\libconcept{input_iterator}@ I, @\libconcept{sentinel_for}@ S1, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> constexpr uninitialized_move_result uninitialized_move(I ifirst, S1 ilast, O ofirst, S2 olast); // freestanding template<@\libconcept{input_range}@ IR, @\exposconcept{nothrow-forward-range}@ OR> requires @\libconcept{constructible_from}@, range_rvalue_reference_t> constexpr uninitialized_move_result, borrowed_iterator_t> uninitialized_move(IR&& in_range, OR&& out_range); // freestanding template using @\libglobal{uninitialized_move_n_result}@ = in_out_result; // freestanding template<@\libconcept{input_iterator}@ I, @\exposconcept{nothrow-forward-iterator}@ O, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> constexpr uninitialized_move_n_result uninitialized_move_n(I ifirst, iter_difference_t n, // freestanding O ofirst, S olast); template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ I, @\libconcept{sized_sentinel_for}@ S1, @\exposconcept{nothrow-random-access-iterator}@ O, @\exposconcept{nothrow-sized-sentinel-for}@ S2> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> uninitialized_move_result uninitialized_move(Ep&& exec, I ifirst, S1 ilast, // freestanding-deleted, O ofirst, S2 olast); // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{sized-random-access-range}@ IR, @\exposconcept{nothrow-sized-random-access-range}@ OR> requires @\libconcept{constructible_from}@, range_rvalue_reference_t> uninitialized_move_result, borrowed_iterator_t> uninitialized_move(Ep&& exec, IR&& in_range, OR&& out_range); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\libconcept{random_access_iterator}@ I, @\exposconcept{nothrow-random-access-iterator}@ O, @\exposconcept{nothrow-sized-sentinel-for}@ S> requires @\libconcept{constructible_from}@, iter_rvalue_reference_t> uninitialized_move_n_result uninitialized_move_n(Ep&& exec, I ifirst, iter_difference_t n, // freestanding-deleted, O ofirst, S olast); // see \ref{algorithms.parallel.overloads} } template::value_type> constexpr void uninitialized_fill(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last, const T& x); template::value_type> void uninitialized_fill(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last, const T& x); template::value_type> constexpr NoThrowForwardIterator uninitialized_fill_n(NoThrowForwardIterator first, Size n, const T& x); // freestanding template::value_type> NoThrowForwardIterator uninitialized_fill_n(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} Size n, const T& x); namespace ranges { template<@\exposconcept{nothrow-forward-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill(I first, S last, const T& x); // freestanding template<@\exposconcept{nothrow-forward-range}@ R, class T = range_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr borrowed_iterator_t uninitialized_fill(R&& r, const T& x); // freestanding template<@\exposconcept{nothrow-forward-iterator}@ I, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> constexpr I uninitialized_fill_n(I first, // freestanding iter_difference_t n, const T& x); template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, @\exposconcept{nothrow-sized-sentinel-for}@ S, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> I uninitialized_fill(Ep&& exec, I first, S last, const T& x); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R, class T = range_value_t> requires @\libconcept{constructible_from}@, const T&> borrowed_iterator_t uninitialized_fill(Ep&& exec, R&& r, // freestanding-deleted, const T& x); // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, class T = iter_value_t> requires @\libconcept{constructible_from}@, const T&> I uninitialized_fill_n(Ep&& exec, I first, // freestanding-deleted, iter_difference_t n, const T& x); // see \ref{algorithms.parallel.overloads} } // \ref{specialized.construct}, \tcode{construct_at} template constexpr T* construct_at(T* location, Args&&... args); // freestanding namespace ranges { template constexpr T* construct_at(T* location, Args&&... args); // freestanding } // \ref{specialized.destroy}, \tcode{destroy} template constexpr void destroy_at(T* location); // freestanding template constexpr void destroy(NoThrowForwardIterator first, // freestanding NoThrowForwardIterator last); template void destroy(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, // see \ref{algorithms.parallel.overloads} NoThrowForwardIterator last); template constexpr NoThrowForwardIterator destroy_n(NoThrowForwardIterator first, // freestanding Size n); template NoThrowForwardIterator destroy_n(ExecutionPolicy&& exec, // freestanding-deleted, NoThrowForwardIterator first, Size n); // see \ref{algorithms.parallel.overloads} namespace ranges { template<@\libconcept{destructible}@ T> constexpr void destroy_at(T* location) noexcept; // freestanding template<@\exposconcept{nothrow-input-iterator}@ I, @\exposconcept{nothrow-sentinel-for}@ S> requires @\libconcept{destructible}@> constexpr I destroy(I first, S last) noexcept; // freestanding template<@\exposconcept{nothrow-input-range}@ R> requires @\libconcept{destructible}@> constexpr borrowed_iterator_t destroy(R&& r) noexcept; // freestanding template<@\exposconcept{nothrow-input-iterator}@ I> requires @\libconcept{destructible}@> constexpr I destroy_n(I first, iter_difference_t n) noexcept; // freestanding template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I, @\exposconcept{nothrow-sized-sentinel-for}@ S> requires @\libconcept{destructible}@> I destroy(Ep&& exec, I first, S last); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-sized-random-access-range}@ R> requires @\libconcept{destructible}@> borrowed_iterator_t destroy(Ep&& exec, R&& r); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} template<@\exposconcept{execution-policy}@ Ep, @\exposconcept{nothrow-random-access-iterator}@ I> requires @\libconcept{destructible}@> I destroy_n(Ep&& exec, I first, iter_difference_t n); // freestanding-deleted, // see \ref{algorithms.parallel.overloads} } // \ref{unique.ptr}, class template \tcode{unique_ptr} template struct default_delete; // freestanding template struct default_delete; // freestanding template> class unique_ptr; // freestanding template class unique_ptr; // freestanding template constexpr unique_ptr make_unique(Args&&... args); // \tcode{T} is not array template constexpr unique_ptr make_unique(size_t n); // \tcode{T} is \tcode{U[]} template @\unspecnc@ make_unique(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} template constexpr unique_ptr make_unique_for_overwrite(); // \tcode{T} is not array template constexpr unique_ptr make_unique_for_overwrite(size_t n); // \tcode{T} is \tcode{U[]} template @\unspecnc@ make_unique_for_overwrite(Args&&...) = delete; // \tcode{T} is \tcode{U[N]} template constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; // freestanding template constexpr bool operator==(const unique_ptr& x, // freestanding const unique_ptr& y); template constexpr bool operator<(const unique_ptr& x, // freestanding const unique_ptr& y); template constexpr bool operator>(const unique_ptr& x, // freestanding const unique_ptr& y); template constexpr bool operator<=(const unique_ptr& x, // freestanding const unique_ptr& y); template constexpr bool operator>=(const unique_ptr& x, // freestanding const unique_ptr& y); template requires @\libconcept{three_way_comparable_with}@::pointer, typename unique_ptr::pointer> constexpr compare_three_way_result_t::pointer, typename unique_ptr::pointer> operator<=>(const unique_ptr& x, const unique_ptr& y); // freestanding template constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; // freestanding template constexpr bool operator<(const unique_ptr& x, nullptr_t); // freestanding template constexpr bool operator<(nullptr_t, const unique_ptr& y); // freestanding template constexpr bool operator>(const unique_ptr& x, nullptr_t); // freestanding template constexpr bool operator>(nullptr_t, const unique_ptr& y); // freestanding template constexpr bool operator<=(const unique_ptr& x, nullptr_t); // freestanding template constexpr bool operator<=(nullptr_t, const unique_ptr& y); // freestanding template constexpr bool operator>=(const unique_ptr& x, nullptr_t); // freestanding template constexpr bool operator>=(nullptr_t, const unique_ptr& y); // freestanding template requires @\libconcept{three_way_comparable}@::pointer> constexpr compare_three_way_result_t::pointer> operator<=>(const unique_ptr& x, nullptr_t); // freestanding template basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); // \ref{util.smartptr.weak.bad}, class \tcode{bad_weak_ptr} class bad_weak_ptr; // \ref{util.smartptr.shared}, class template \tcode{shared_ptr} template class shared_ptr; // \ref{util.smartptr.shared.create}, \tcode{shared_ptr} creation template constexpr shared_ptr make_shared(Args&&... args); // \tcode{T} is not array template constexpr shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array template constexpr shared_ptr make_shared(size_t N); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} template constexpr shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} template constexpr shared_ptr make_shared(size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr allocate_shared(const A& a, size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} template constexpr shared_ptr allocate_shared(const A& a, // \tcode{T} is \tcode{U[N]} const remove_extent_t& u); template constexpr shared_ptr make_shared_for_overwrite(); // \tcode{T} is not \tcode{U[]} template constexpr shared_ptr allocate_shared_for_overwrite(const A& a); // \tcode{T} is not \tcode{U[]} template constexpr shared_ptr make_shared_for_overwrite(size_t N); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); // \tcode{T} is \tcode{U[]} // \ref{util.smartptr.shared.cmp}, \tcode{shared_ptr} comparisons template constexpr bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; template constexpr strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; template constexpr bool operator==(const shared_ptr& x, nullptr_t) noexcept; template constexpr strong_ordering operator<=>(const shared_ptr& x, nullptr_t) noexcept; // \ref{util.smartptr.shared.spec}, \tcode{shared_ptr} specialized algorithms template constexpr void swap(shared_ptr& a, shared_ptr& b) noexcept; // \ref{util.smartptr.shared.cast}, \tcode{shared_ptr} casts template constexpr shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; template constexpr shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; template constexpr shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; template shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; template shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; // \ref{util.smartptr.getdeleter}, \tcode{shared_ptr} \tcode{get_deleter} template constexpr D* get_deleter(const shared_ptr& p) noexcept; // \ref{util.smartptr.shared.io}, \tcode{shared_ptr} I/O template basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); // \ref{util.smartptr.weak}, class template \tcode{weak_ptr} template class weak_ptr; // \ref{util.smartptr.weak.spec}, \tcode{weak_ptr} specialized algorithms template constexpr void swap(weak_ptr& a, weak_ptr& b) noexcept; // \ref{util.smartptr.ownerless}, class template \tcode{owner_less} template struct owner_less; // \ref{util.smartptr.owner.hash}, struct \tcode{owner_hash} struct owner_hash; // \ref{util.smartptr.owner.equal}, struct \tcode{owner_equal} struct owner_equal; // \ref{util.smartptr.enab}, class template \tcode{enable_shared_from_this} template class enable_shared_from_this; // \ref{util.smartptr.hash}, hash support template struct hash; // freestanding template struct hash>; // freestanding template struct hash>; // \ref{util.smartptr.atomic}, atomic smart pointers template struct atomic; // freestanding template struct atomic>; template struct atomic>; // \ref{out.ptr.t}, class template \tcode{out_ptr_t} template class out_ptr_t; // freestanding // \ref{out.ptr}, function template \tcode{out_ptr} template constexpr auto out_ptr(Smart& s, Args&&... args); // freestanding // \ref{inout.ptr.t}, class template \tcode{inout_ptr_t} template class inout_ptr_t; // freestanding // \ref{inout.ptr}, function template \tcode{inout_ptr} template constexpr auto inout_ptr(Smart& s, Args&&... args); // freestanding // \ref{indirect}, class template \tcode{indirect} template> class indirect; // \ref{indirect.hash}, hash support template struct hash>; // \ref{polymorphic}, class template \tcode{polymorphic} template> class polymorphic; namespace pmr { template using indirect = indirect>; template using polymorphic = polymorphic>; } } \end{codeblock} \rSec2[pointer.traits]{Pointer traits} \rSec3[pointer.traits.general]{General} \pnum The class template \tcode{pointer_traits} supplies a uniform interface to certain attributes of pointer-like types. \indexlibraryglobal{pointer_traits}% \begin{codeblock} namespace std { template struct pointer_traits { @\seebelow@; }; template struct pointer_traits { using pointer = T*; using element_type = T; using difference_type = ptrdiff_t; template using rebind = U*; static constexpr pointer pointer_to(@\seebelow@ r) noexcept; }; } \end{codeblock} \rSec3[pointer.traits.types]{Member types} \pnum The definitions in this subclause make use of the following exposition-only class template and concept: \begin{codeblock} template struct @\exposid{ptr-traits-elem}@ // \expos { }; template requires requires { typename T::element_type; } struct @\exposid{ptr-traits-elem}@ { using type = T::element_type; }; template class SomePointer, class T, class... Args> requires (!requires { typename SomePointer::element_type; }) struct @\exposid{ptr-traits-elem}@> { using type = T; }; template concept @\defexposconcept{has-elem-type}@ = // \expos requires { typename @\exposid{ptr-traits-elem}@::type; } \end{codeblock} \pnum If \tcode{Ptr} satisfies \exposconcept{has-elem-type}, a specialization \tcode{pointer_traits} generated from the \tcode{pointer_traits} primary template has the following members as well as those described in~\ref{pointer.traits.functions}; otherwise, such a specialization has no members by any of those names. \indexlibrarymember{pointer}{pointer_traits}% \begin{itemdecl} using pointer = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Ptr}. \end{itemdescr} \indexlibrarymember{element_type}{pointer_traits}% \begin{itemdecl} using element_type = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{typename \exposid{ptr-traits-elem}::type}. \end{itemdescr} \indexlibrarymember{difference_type}{pointer_traits}% \begin{itemdecl} using difference_type = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Ptr::difference_type} if the \grammarterm{qualified-id} \tcode{Ptr::difference_type} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{ptrdiff_t}. \end{itemdescr} \indexlibrarymember{rebind}{pointer_traits}% \begin{itemdecl} template using rebind = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \templalias \tcode{Ptr::rebind} if the \grammarterm{qualified-id} \tcode{Ptr::rebind} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{SomePointer} if \tcode{Ptr} is a class template specialization of the form \tcode{SomePointer}, where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of \tcode{rebind} is ill-formed. \end{itemdescr} \rSec3[pointer.traits.functions]{Member functions} \indexlibrarymember{pointer_to}{pointer_traits}% \begin{itemdecl} static constexpr pointer pointer_traits::pointer_to(@\seebelow@ r); static constexpr pointer pointer_traits::pointer_to(@\seebelow@ r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates For the first member function, \tcode{Ptr::pointer_to(r)} is well-formed. \pnum \expects For the first member function, \tcode{Ptr::pointer_to(r)} returns a pointer to \tcode{r} through which indirection is valid. \pnum \returns The first member function returns \tcode{Ptr::pointer_to(r)}. The second member function returns \tcode{addressof(r)}. \pnum \remarks If \tcode{element_type} is \cv{}~\keyword{void}, the type of \tcode{r} is unspecified; otherwise, it is \tcode{element_type\&}. \end{itemdescr} \rSec3[pointer.traits.optmem]{Optional members} \pnum Specializations of \tcode{pointer_traits} may define the member declared in this subclause to customize the behavior of the standard library. A specialization generated from the \tcode{pointer_traits} primary template has no member by this name. \indexlibrarymember{to_address}{pointer_traits}% \begin{itemdecl} static element_type* to_address(pointer p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A pointer of type \tcode{element_type*} that references the same location as the argument \tcode{p}. \pnum \begin{note} This function is intended to be the inverse of \tcode{pointer_to}. If defined, it customizes the behavior of the non-member function \tcode{to_address}\iref{pointer.conversion}. \end{note} \end{itemdescr} \rSec2[pointer.conversion]{Pointer conversion} \indexlibraryglobal{to_address}% \begin{itemdecl} template constexpr T* to_address(T* p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is not a function type. \pnum \returns \tcode{p}. \end{itemdescr} \indexlibraryglobal{to_address}% \begin{itemdecl} template constexpr auto to_address(const Ptr& p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{pointer_traits::to_address(p)} if that expression is well-formed (see \ref{pointer.traits.optmem}), otherwise \tcode{to_address(p.operator->())}. \end{itemdescr} \rSec2[ptr.align]{Pointer alignment} \indexlibraryglobal{align}% \begin{itemdecl} void* align(size_t alignment, size_t size, void*& ptr, size_t& space); \end{itemdecl} \begin{itemdescr} \pnum \expects \begin{itemize} \item \tcode{alignment} is a power of two \item \tcode{ptr} represents the address of contiguous storage of at least \tcode{space} bytes \end{itemize} \pnum \effects If it is possible to fit \tcode{size} bytes of storage aligned by \tcode{alignment} into the buffer pointed to by \tcode{ptr} with length \tcode{space}, the function updates \tcode{ptr} to represent the first possible address of such storage and decreases \tcode{space} by the number of bytes used for alignment. Otherwise, the function does nothing. \pnum \returns A null pointer if the requested aligned buffer would not fit into the available space, otherwise the adjusted value of \tcode{ptr}. \pnum \begin{note} The function updates its \tcode{ptr} and \tcode{space} arguments so that it can be called repeatedly with possibly different \tcode{alignment} and \tcode{size} arguments for the same buffer. \end{note} \end{itemdescr} \indexlibraryglobal{assume_aligned}% \begin{itemdecl} template constexpr T* assume_aligned(T* ptr); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{N} is a power of two. \pnum \expects \tcode{ptr} points to an object $X$ of a type similar\iref{conv.qual} to \tcode{T}, where $X$ has alignment \tcode{N}\iref{basic.align}. \pnum \returns \tcode{ptr}. \pnum \throws Nothing. \pnum \begin{note} The alignment assumption on an object $X$ expressed by a call to \tcode{assume_aligned} might result in generation of more efficient code. It is up to the program to ensure that the assumption actually holds. The call does not cause the implementation to verify or enforce this. An implementation might only make the assumption for those operations on $X$ that access $X$ through the pointer returned by \tcode{assume_aligned}. \end{note} \end{itemdescr} \indexlibraryglobal{is_sufficiently_aligned}% \begin{itemdecl} template bool is_sufficiently_aligned(T* ptr); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{Alignment} is a power of two. \pnum \expects \tcode{p} points to an object \tcode{X} of a type similar\iref{conv.qual} to \tcode{T}. \pnum \returns \tcode{true} if \tcode{X} has alignment at least \tcode{Alignment}, otherwise \tcode{false}. \pnum \throws Nothing. \end{itemdescr} \rSec2[obj.lifetime]{Explicit lifetime management} \indexlibraryglobal{start_lifetime}% \begin{itemdecl} template constexpr void start_lifetime(T& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type and an implicit-lifetime\iref{basic.types} aggregate\iref{dcl.init.aggr}. \pnum \effects If the object referenced by \tcode{r} is already within its lifetime\iref{basic.life}, no effects. Otherwise, begins the lifetime of the object referenced by \tcode{r}. \begin{note} No initialization is performed and no subobject has its lifetime started. If \tcode{r} denotes a member of a union $U$, it becomes the active member of $U$\iref{class.union}. \end{note} \end{itemdescr} \indexlibraryglobal{start_lifetime_as}% \begin{itemdecl} template T* start_lifetime_as(void* p) noexcept; template const T* start_lifetime_as(const void* p) noexcept; template volatile T* start_lifetime_as(volatile void* p) noexcept; template const volatile T* start_lifetime_as(const volatile void* p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is an implicit-lifetime type\iref{term.implicit.lifetime.type} and not an incomplete type\iref{term.incomplete.type}. \pnum \expects \range{p}{(char*)p + sizeof(T)} denotes a region of allocated storage that is a subset of the region of storage reachable through\iref{basic.compound} \tcode{p} and suitably aligned for the type \tcode{T}. \pnum \effects Implicitly creates objects\iref{intro.object} within the denoted region consisting of an object \placeholder{a} of type \tcode{T} whose address is \tcode{p}, and objects nested within \placeholder{a}, as follows: The object representation of \placeholder{a} is the contents of the storage prior to the call to \tcode{start_lifetime_as}. The value of each created object \placeholder{o} of trivially copyable type\iref{term.trivially.copyable.type} \tcode{U} is determined in the same manner as for a call to \tcode{bit_cast(E)}\iref{bit.cast}, where \tcode{E} is an lvalue of type \tcode{U} denoting \placeholder{o}, except that the storage is not accessed. The value of any other created object is unspecified. \begin{note} The unspecified value can be indeterminate. \end{note} \pnum \returns % FIXME: We should introduce "a" outside of the \effects clause A pointer to the \placeholder{a} defined in the \Fundescx{Effects} paragraph. \end{itemdescr} \indexlibraryglobal{start_lifetime_as_array}% \begin{itemdecl} template T* start_lifetime_as_array(void* p, size_t n) noexcept; template const T* start_lifetime_as_array(const void* p, size_t n) noexcept; template volatile T* start_lifetime_as_array(volatile void* p, size_t n) noexcept; template const volatile T* start_lifetime_as_array(const volatile void* p, size_t n) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type. \pnum \expects \tcode{p} is suitably aligned for an array of \tcode{T} or is null. \tcode{n <= size_t(-1) / sizeof(T)} is \tcode{true}. If \tcode{n > 0} is \tcode{true}, \range{(char*)p}{(char*)p + (n * sizeof(T))} denotes a region of allocated storage that is a subset of the region of storage reachable through\iref{basic.compound} \tcode{p}. \pnum \effects If \tcode{n > 0} is \tcode{true}, equivalent to \tcode{start_lifetime_as(p)} where \tcode{U} is the type ``array of \tcode{n} \tcode{T}''. Otherwise, there are no effects. \pnum \returns A pointer to the first element of the created array, if any; otherwise, a pointer that compares equal to \tcode{p}\iref{expr.eq}. \end{itemdescr} \rSec2[allocator.tag]{Allocator argument tag} \indexlibraryglobal{allocator_arg_t}% \indexlibraryglobal{allocator_arg}% \begin{itemdecl} namespace std { struct allocator_arg_t { explicit allocator_arg_t() = default; }; inline constexpr allocator_arg_t allocator_arg{}; } \end{itemdecl} \pnum The \tcode{allocator_arg_t} struct is an empty class type used as a unique type to disambiguate constructor and function overloading. Specifically, several types (see \tcode{tuple}~\ref{tuple}) have constructors with \tcode{allocator_arg_t} as the first argument, immediately followed by an argument of a type that meets the \oldconceptref{Allocator} requirements\iref{allocator.requirements.general}. \rSec2[allocator.uses]{\tcode{uses_allocator}} \rSec3[allocator.uses.trait]{\tcode{uses_allocator} trait} \indexlibraryglobal{uses_allocator}% \begin{itemdecl} template struct uses_allocator; \end{itemdecl} \begin{itemdescr} \pnum \remarks Automatically detects whether \tcode{T} has a nested \tcode{allocator_type} that is convertible from \tcode{Alloc}. Meets the \oldconceptref{BinaryTypeTrait} requirements\iref{meta.rqmts}. The implementation shall provide a definition that is derived from \tcode{true_type} if the \grammarterm{qualified-id} \tcode{T::allocator_type} is valid and denotes a type\iref{temp.deduct} and \tcode{is_convertible_v != false}, otherwise it shall be derived from \tcode{false_type}. A program may specialize this template to derive from \tcode{true_type} for a program-defined type \tcode{T} that does not have a nested \tcode{allocator_type} but nonetheless can be constructed with an allocator where either: \begin{itemize} \item the first argument of a constructor has type \tcode{allocator_arg_t} and the second argument has type \tcode{Alloc} or \item the last argument of a constructor has type \tcode{Alloc}. \end{itemize} \end{itemdescr} \rSec3[allocator.uses.construction]{Uses-allocator construction} \pnum \defnx{Uses-allocator construction}{uses-allocator construction} with allocator \tcode{alloc} and constructor arguments \tcode{args...} refers to the construction of an object of type \tcode{T} such that \tcode{alloc} is passed to the constructor of \tcode{T} if \tcode{T} uses an allocator type compatible with \tcode{alloc}. When applied to the construction of an object of type \tcode{T}, it is equivalent to initializing it with the value of the expression \tcode{make_obj_using_allocator(alloc, args...)}, described below. \pnum The following utility functions support three conventions for passing \tcode{alloc} to a constructor: \begin{itemize} \item If \tcode{T} does not use an allocator compatible with \tcode{alloc}, then \tcode{alloc} is ignored. \item Otherwise, if \tcode{T} has a constructor invocable as \tcode{T(allocator_arg_t\{\}, alloc, args...)} (leading-allocator convention), then uses-allocator construction chooses this constructor form. \item Otherwise, if \tcode{T} has a constructor invocable as \tcode{T(args..., alloc)} (trailing-allocator convention), then uses-allocator construction chooses this constructor form. \end{itemize} \pnum The \tcode{uses_allocator_construction_args} function template takes an allocator and argument list and produces (as a tuple) a new argument list matching one of the above conventions. Additionally, overloads are provided that treat specializations of \tcode{pair} such that uses-allocator construction is applied individually to the \tcode{first} and \tcode{second} data members. The \tcode{make_obj_using_allocator} and \tcode{uninitialized_construct_using_allocator} function templates apply the modified constructor arguments to construct an object of type \tcode{T} as a return value or in-place, respectively. \begin{note} For \tcode{uses_allocator_construction_args} and \tcode{make_obj_using_allocator}, type \tcode{T} is not deduced and must therefore be specified explicitly by the caller. \end{note} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, Args&&... args) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is not a specialization of \tcode{pair}. \pnum \returns A \tcode{tuple} value determined as follows: \begin{itemize} \item If \tcode{uses_allocator_v, Alloc>} is \tcode{false} and \tcode{is_constructible_v} is \tcode{true}, return \tcode{forward_as_tuple(std::forward(args)...)}. \item Otherwise, if \tcode{uses_allocator_v, Alloc>} is \tcode{true} and \tcode{is_constructible_v} is \tcode{true}, return \begin{codeblock} tuple( allocator_arg, alloc, std::forward(args)...) \end{codeblock} \item Otherwise, if \tcode{uses_allocator_v, Alloc>} is \tcode{true} and \tcode{is_constructible_v} is \tcode{true}, return \tcode{forward_as_tuple(std::forward(args)..., alloc)}. \item Otherwise, the program is ill-formed. \end{itemize} \begin{note} This definition prevents a silent failure to pass the allocator to a constructor of a type for which \tcode{uses_allocator_v} is \tcode{true}. \end{note} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, piecewise_construct_t, Tuple1&& x, Tuple2&& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{T1} be \tcode{T::first_type}. Let \tcode{T2} be \tcode{T::second_type}. \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}. \pnum \effects Equivalent to: \begin{codeblock} return make_tuple( piecewise_construct, apply([&alloc](auto&&... args1) { return uses_allocator_construction_args( alloc, std::forward(args1)...); }, std::forward(x)), apply([&alloc](auto&&... args2) { return uses_allocator_construction_args( alloc, std::forward(args2)...); }, std::forward(y))); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}. \pnum \effects Equivalent to: \begin{codeblock} return uses_allocator_construction_args(alloc, piecewise_construct, tuple<>{}, tuple<>{}); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u, V&& v) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}. \pnum \effects Equivalent to: \begin{codeblock} return uses_allocator_construction_args(alloc, piecewise_construct, forward_as_tuple(std::forward(u)), forward_as_tuple(std::forward(v))); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair& pr) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}. \pnum \effects Equivalent to: \begin{codeblock} return uses_allocator_construction_args(alloc, piecewise_construct, forward_as_tuple(pr.first), forward_as_tuple(pr.second)); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, pair&& pr) noexcept; template constexpr auto uses_allocator_construction_args(const Alloc& alloc, const pair&& pr) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}. \pnum \effects Equivalent to: \begin{codeblock} return uses_allocator_construction_args(alloc, piecewise_construct, forward_as_tuple(get<0>(std::move(pr))), forward_as_tuple(get<1>(std::move(pr)))); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, P&& p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair} and \tcode{remove_cvref_t

} is not a specialization of \tcode{ranges::subrange}. \pnum \effects Equivalent to: \begin{codeblock} return uses_allocator_construction_args(alloc, piecewise_construct, forward_as_tuple(get<0>(std::forward

(p))), forward_as_tuple(get<1>(std::forward

(p)))); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uses_allocator_construction_args}% \begin{itemdecl} template constexpr auto uses_allocator_construction_args(const Alloc& alloc, U&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum Let \exposid{FUN} be the function template: \begin{codeblock} template void @\exposid{FUN}@(const pair&); \end{codeblock} \pnum \constraints \tcode{remove_cv_t} is a specialization of \tcode{pair}, and either: \begin{itemize} \item \tcode{remove_cvref_t} is a specialization of \tcode{ranges::subrange}, or \item \tcode{U} does not satisfy \exposconcept{pair-like} and the expression \tcode{\exposid{FUN}(u)} is not well-formed when considered as an unevaluated operand. \end{itemize} \pnum Let \exposid{pair-constructor} be an exposition-only class defined as follows: \begin{codeblock} class @\exposid{pair-constructor}@ { using @\exposid{pair-type}@ = remove_cv_t; // \expos constexpr auto @\exposid{do-construct}@(const @\exposid{pair-type}@& p) const { // \expos return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, p); } constexpr auto @\exposid{do-construct}@(@\exposid{pair-type}@&& p) const { // \expos return make_obj_using_allocator<@\exposid{pair-type}@>(@\exposid{alloc_}@, std::move(p)); } const Alloc& @\exposid{alloc_}@; // \expos U& @\exposid{u_}@; // \expos public: constexpr operator @\exposid{pair-type}@() const { return @\exposid{do-construct}@(std::forward(@\exposid{u_}@)); } }; \end{codeblock} \pnum \returns \tcode{make_tuple(pc)}, where \tcode{pc} is a \exposid{pair-constructor} object whose \exposid{alloc_} member is initialized with \tcode{alloc} and whose \exposid{u_} member is initialized with \tcode{u}. \end{itemdescr} \indexlibraryglobal{make_obj_using_allocator}% \begin{itemdecl} template constexpr T make_obj_using_allocator(const Alloc& alloc, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return make_from_tuple(uses_allocator_construction_args( alloc, std::forward(args)...)); \end{codeblock} \end{itemdescr} \indexlibraryglobal{uninitialized_construct_using_allocator}% \begin{itemdecl} template constexpr T* uninitialized_construct_using_allocator(T* p, const Alloc& alloc, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} return apply([&](U&&... xs) { return construct_at(p, std::forward(xs)...); }, uses_allocator_construction_args(alloc, std::forward(args)...)); \end{codeblock} \end{itemdescr} \rSec2[allocator.traits]{Allocator traits} \rSec3[allocator.traits.general]{General} \pnum The class template \tcode{allocator_traits} supplies a uniform interface to all allocator types. An allocator cannot be a non-class type, however, even if \tcode{allocator_traits} supplies the entire required interface. \begin{note} Thus, it is always possible to create a derived class from an allocator. \end{note} If a program declares an explicit or partial specialization of \tcode{allocator_traits}, the program is ill-formed, no diagnostic required. \indexlibraryglobal{allocator_traits}% \begin{codeblock} namespace std { template struct allocator_traits { using allocator_type = Alloc; using value_type = Alloc::value_type; using pointer = @\seebelow@; using const_pointer = @\seebelow@; using void_pointer = @\seebelow@; using const_void_pointer = @\seebelow@; using difference_type = @\seebelow@; using size_type = @\seebelow@; using propagate_on_container_copy_assignment = @\seebelow@; using propagate_on_container_move_assignment = @\seebelow@; using propagate_on_container_swap = @\seebelow@; using is_always_equal = @\seebelow@; template using rebind_alloc = @\seebelow@; template using rebind_traits = allocator_traits>; static constexpr pointer allocate(Alloc& a, size_type n); static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); static constexpr allocation_result allocate_at_least(Alloc& a, size_type n); static constexpr void deallocate(Alloc& a, pointer p, size_type n); template static constexpr void construct(Alloc& a, T* p, Args&&... args); template static constexpr void destroy(Alloc& a, T* p); static constexpr size_type max_size(const Alloc& a) noexcept; static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); }; } \end{codeblock} \rSec3[allocator.traits.types]{Member types} \indexlibrarymember{pointer}{allocator_traits}% \begin{itemdecl} using pointer = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::pointer} if the \grammarterm{qualified-id} \tcode{Alloc::pointer} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{value_type*}. \end{itemdescr} \indexlibrarymember{const_pointer}{allocator_traits}% \begin{itemdecl} using const_pointer = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::const_pointer} if the \grammarterm{qualified-id} \tcode{Alloc::const_pointer} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{pointer_traits::rebind<\brk{}const value_type>}. \end{itemdescr} \indexlibrarymember{void_pointer}{allocator_traits}% \begin{itemdecl} using void_pointer = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::void_pointer} if the \grammarterm{qualified-id} \tcode{Alloc::void_pointer} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{pointer_traits::rebind<\brk{}void>}. \end{itemdescr} \indexlibrarymember{const_void_pointer}{allocator_traits}% \begin{itemdecl} using const_void_pointer = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::const_void_pointer} if the \grammarterm{qualified-id} \tcode{Alloc::const_void_pointer} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{pointer_traits::\brk{}rebind}. \end{itemdescr} \indexlibrarymember{difference_type}{allocator_traits}% \begin{itemdecl} using difference_type = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::difference_type} if the \grammarterm{qualified-id} \tcode{Alloc::difference_type} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{pointer_traits::dif\-ference_type}. \end{itemdescr} \indexlibrarymember{size_type}{allocator_traits}% \begin{itemdecl} using size_type = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::size_type} if the \grammarterm{qualified-id} \tcode{Alloc::size_type} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{make_unsigned_t}. \end{itemdescr} \indexlibrarymember{propagate_on_container_copy_assignment}{allocator_traits}% \begin{itemdecl} using propagate_on_container_copy_assignment = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::propagate_on_container_copy_assignment} if the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_copy_assignment} is valid and denotes a type\iref{temp.deduct}; otherwise \tcode{false_type}. \end{itemdescr} \indexlibrarymember{propagate_on_container_move_assignment}{allocator_traits}% \begin{itemdecl} using propagate_on_container_move_assignment = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::propagate_on_container_move_assignment} if the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_move_assignment} is valid and denotes a type\iref{temp.deduct}; otherwise \tcode{false_type}. \end{itemdescr} \indexlibrarymember{propagate_on_container_swap}{allocator_traits}% \begin{itemdecl} using propagate_on_container_swap = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::propagate_on_container_swap} if the \grammarterm{qualified-id} \tcode{Alloc::propagate_on_container_swap} is valid and denotes a type\iref{temp.deduct}; otherwise \tcode{false_type}. \end{itemdescr} \indexlibrarymember{is_always_equal}{allocator_traits}% \begin{itemdecl} using is_always_equal = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{Alloc::is_always_equal} if the \grammarterm{qualified-id} \tcode{Alloc::is_always_equal} is valid and denotes a type\iref{temp.deduct}; otherwise \tcode{is_empty::type}. \end{itemdescr} \indexlibrarymember{rebind_alloc}{allocator_traits}% \begin{itemdecl} template using rebind_alloc = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \templalias \tcode{Alloc::rebind::other} if the \grammarterm{qualified-id} \tcode{Alloc::rebind::other} is valid and denotes a type\iref{temp.deduct}; otherwise, \tcode{Alloc} if \tcode{Alloc} is a class template specialization of the form \tcode{Alloc}, where \tcode{Args} is zero or more type arguments; otherwise, the instantiation of \tcode{rebind_alloc} is ill-formed. \end{itemdescr} \rSec3[allocator.traits.members]{Static member functions} \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} static constexpr pointer allocate(Alloc& a, size_type n); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{a.allocate(n)}. \end{itemdescr} \indexlibrarymember{allocate}{allocator_traits}% \begin{itemdecl} static constexpr pointer allocate(Alloc& a, size_type n, const_void_pointer hint); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{a.allocate(n, hint)} if that expression is well-formed; otherwise, \tcode{a.allocate(n)}. \end{itemdescr} \indexlibrarymember{allocate_at_least}{allocator_traits}% \begin{itemdecl} static constexpr allocation_result allocate_at_least(Alloc& a, size_type n); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{a.allocate_at_least(n)} if that expression is well-formed; otherwise, \tcode{\{a.allocate(n), n\}}. \end{itemdescr} \indexlibrarymember{deallocate}{allocator_traits}% \begin{itemdecl} static constexpr void deallocate(Alloc& a, pointer p, size_type n); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{a.deallocate(p, n)}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{construct}{allocator_traits}% \begin{itemdecl} template static constexpr void construct(Alloc& a, T* p, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{a.construct(p, std::forward(args)...)} if that call is well-formed; otherwise, invokes \tcode{construct_at(p, std::forward(args)...)}. \end{itemdescr} \indexlibrarymember{destroy}{allocator_traits}% \begin{itemdecl} template static constexpr void destroy(Alloc& a, T* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{a.destroy(p)} if that call is well-formed; otherwise, invokes \tcode{destroy_at(p)}. \end{itemdescr} \indexlibrarymember{max_size}{allocator_traits}% \begin{itemdecl} static constexpr size_type max_size(const Alloc& a) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{a.max_size()} if that expression is well-formed; otherwise, \tcode{numeric_limits::\brk{}max() / sizeof(value_type)}. \end{itemdescr} \indexlibrarymember{select_on_container_copy_construction}{allocator_traits}% \begin{itemdecl} static constexpr Alloc select_on_container_copy_construction(const Alloc& rhs); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{rhs.select_on_container_copy_construction()} if that expression is well-formed; otherwise, \tcode{rhs}. \end{itemdescr} \rSec3[allocator.traits.other]{Other} \pnum The class template \tcode{allocation_result} has the template parameters, data members, and special members specified above. It has no base classes or members other than those specified. \rSec2[default.allocator]{The default allocator} \rSec3[default.allocator.general]{General} \pnum All specializations of the default allocator meet the allocator completeness requirements\iref{allocator.requirements.completeness}. \indexlibraryglobal{allocator}% \indexlibrarymember{value_type}{allocator}% \indexlibrarymember{size_type}{allocator}% \indexlibrarymember{difference_type}{allocator}% \indexlibrarymember{propagate_on_container_move_assignment}{allocator}% \indexlibrarymember{operator=}{allocator}% \begin{codeblock} namespace std { template class allocator { public: using value_type = T; using size_type = size_t; using difference_type = ptrdiff_t; using propagate_on_container_move_assignment = true_type; constexpr allocator() noexcept; constexpr allocator(const allocator&) noexcept; template constexpr allocator(const allocator&) noexcept; constexpr ~allocator(); constexpr allocator& operator=(const allocator&) = default; constexpr T* allocate(size_t n); constexpr allocation_result allocate_at_least(size_t n); constexpr void deallocate(T* p, size_t n); }; } \end{codeblock} \pnum \tcode{allocator_traits>::is_always_equal::value} is \tcode{true} for any \tcode{T}. \rSec3[allocator.members]{Members} \pnum Except for the destructor, member functions of the default allocator shall not introduce data races\iref{intro.multithread} as a result of concurrent calls to those member functions from different threads. Calls to these functions that allocate or deallocate a particular unit of storage shall occur in a single total order, and each such deallocation call shall happen before the next allocation (if any) in this order. \indexlibrarymember{allocate}{allocator}% \begin{itemdecl} constexpr T* allocate(size_t n); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is not an incomplete type\iref{term.incomplete.type}. \pnum \returns A pointer to the initial element of an array of \tcode{n} \tcode{T}. \pnum \throws \tcode{bad_array_new_length} if \tcode{numeric_limits::max() / sizeof(T) < n}, or \tcode{bad_alloc} if the storage cannot be obtained. \pnum \remarks The storage for the array is obtained by calling \tcode{::operator new}\iref{new.delete}, but it is unspecified when or how often this function is called. This function starts the lifetime of the array object, but not that of any of the array elements. \end{itemdescr} \indexlibrarymember{allocate_at_least}{allocator}% \begin{itemdecl} constexpr allocation_result allocate_at_least(size_t n); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is not an incomplete type\iref{term.incomplete.type}. \pnum \returns \tcode{allocation_result\{ptr, count\}}, where \tcode{ptr} is a pointer to the initial element of an array of \tcode{count} \tcode{T} and $\tcode{count} \geq \tcode{n}$. \pnum \throws \tcode{bad_array_new_length} if $\tcode{numeric_limits::max() / sizeof(T)} < \tcode{n}$, or \tcode{bad_alloc} if the storage cannot be obtained. \pnum \remarks The storage for the array is obtained by calling \tcode{::operator new}, but it is unspecified when or how often this function is called. This function starts the lifetime of the array object, but not that of any of the array elements. \end{itemdescr} \indexlibrarymember{deallocate}{allocator}% \begin{itemdecl} constexpr void deallocate(T* p, size_t n); \end{itemdecl} \begin{itemdescr} \pnum \expects \begin{itemize} \item If \tcode{p} is memory that was obtained by a call to \tcode{allocate_at_least}, let \tcode{ret} be the value returned and \tcode{req} be the value passed as the first argument to that call. \tcode{p} is equal to \tcode{ret.ptr} and \tcode{n} is a value such that $\tcode{req} \leq \tcode{n} \leq \tcode{ret.count}$. \item Otherwise, \tcode{p} is a pointer value obtained from \tcode{allocate}. \tcode{n} equals the value passed as the first argument to the invocation of \tcode{allocate} which returned \tcode{p}. \end{itemize} \pnum \effects Deallocates the storage referenced by \tcode{p}. \pnum \remarks Uses \tcode{::operator delete}\iref{new.delete}, but it is unspecified when this function is called. \end{itemdescr} \rSec3[allocator.globals]{Operators} \indexlibrarymember{operator==}{allocator}% \begin{itemdecl} template constexpr bool operator==(const allocator&, const allocator&) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true}. \end{itemdescr} \rSec2[specialized.addressof]{\tcode{addressof}} \indexlibraryglobal{addressof}% \begin{itemdecl} template constexpr T* addressof(T& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The actual address of the object or function referenced by \tcode{r}, even in the presence of an overloaded \tcode{operator\&}. \pnum \remarks An expression \tcode{addressof(E)} is a constant subexpression\iref{defns.const.subexpr} if \tcode{E} is an lvalue constant subexpression. \end{itemdescr} \rSec2[c.malloc]{C library memory allocation} \pnum \begin{note} The header \libheaderref{cstdlib} declares the functions described in this subclause. \end{note} \indexlibraryglobal{aligned_alloc}% \indexlibraryglobal{calloc}% \indexlibraryglobal{malloc}% \begin{itemdecl} void* aligned_alloc(size_t alignment, size_t size); void* calloc(size_t nmemb, size_t size); void* malloc(size_t size); \end{itemdecl} \begin{itemdescr} \pnum \effects These functions have the semantics specified in the C standard library. \pnum \remarks These functions do not attempt to allocate storage by calling \tcode{::operator new()}\iref{new.delete}. \indexlibrarymember{new}{operator}% \pnum These functions implicitly create objects\iref{intro.object} in the returned region of storage and return a pointer to a suitable created object. In the case of \tcode{calloc}, the objects are created before the storage is zeroed. \end{itemdescr} \indexlibraryglobal{realloc}% \begin{itemdecl} void* realloc(void* ptr, size_t size); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{free(ptr)} has well-defined behavior. \pnum \effects If \tcode{ptr} is not null and \tcode{size} is zero, the behavior is erroneous and the effects are implementation-defined. Otherwise, this function has the semantics specified in the C standard library. \pnum \remarks This function does not attempt to allocate storage by calling \tcode{::operator new()}\iref{new.delete}. When a non-null pointer is returned, this function implicitly creates objects\iref{intro.object} in the returned region of storage and returns a pointer to a suitable created object. The objects are created before the storage is copied. \end{itemdescr} \indexlibraryglobal{free}% \begin{itemdecl} void free(void* ptr); \end{itemdecl} \begin{itemdescr} \pnum \effects This function has the semantics specified in the C standard library. \pnum \remarks This function does not attempt to deallocate storage by calling \tcode{::operator delete()}\indexlibrarymember{delete}{operator}. \end{itemdescr} \xrefc{7.24.4} \rSec1[smartptr]{Smart pointers} \rSec2[unique.ptr]{Unique-ownership pointers} \rSec3[unique.ptr.general]{General} \pnum A \defn{unique pointer} is an object that owns another object and manages that other object through a pointer. More precisely, a unique pointer is an object \textit{u} that stores a pointer to a second object \textit{p} and will dispose of \textit{p} when \textit{u} is itself destroyed (e.g., when leaving block scope\iref{stmt.dcl}). In this context, \textit{u} is said to \defn{own} \tcode{p}. \pnum The mechanism by which \textit{u} disposes of \textit{p} is known as \textit{p}'s associated \defn{deleter}, a function object whose correct invocation results in \textit{p}'s appropriate disposition (typically its deletion). \pnum Let the notation \textit{u.p} denote the pointer stored by \textit{u}, and let \textit{u.d} denote the associated deleter. Upon request, \textit{u} can \defn{reset} (replace) \textit{u.p} and \textit{u.d} with another pointer and deleter, but properly disposes of its owned object via the associated deleter before such replacement is considered completed. \pnum Each object of a type \tcode{U} instantiated from the \tcode{unique_ptr} template specified in \ref{unique.ptr} has the strict ownership semantics, specified above, of a unique pointer. In partial satisfaction of these semantics, each such \tcode{U} is \oldconceptref{MoveConstructible} and \oldconceptref{MoveAssignable}, but is not \oldconceptref{CopyConstructible} nor \oldconceptref{CopyAssignable}. The template parameter \tcode{T} of \tcode{unique_ptr} may be an incomplete type. \pnum \begin{note} The uses of \tcode{unique_ptr} include providing exception safety for dynamically allocated memory, passing ownership of dynamically allocated memory to a function, and returning dynamically allocated memory from a function. \end{note} \rSec3[unique.ptr.dltr]{Default deleters} \rSec4[unique.ptr.dltr.general]{General} \pnum The class template \tcode{default_delete} serves as the default deleter (destruction policy) for the class template \tcode{unique_ptr}. \pnum The template parameter \tcode{T} of \tcode{default_delete} may be an incomplete type. \rSec4[unique.ptr.dltr.dflt]{\tcode{default_delete}} \begin{codeblock} namespace std { template struct default_delete { constexpr default_delete() noexcept = default; template constexpr default_delete(const default_delete&) noexcept; constexpr void operator()(T*) const; }; } \end{codeblock} \indexlibraryctor{default_delete}% \begin{itemdecl} template constexpr default_delete(const default_delete& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{U*} is implicitly convertible to \tcode{T*}. \pnum \effects Constructs a \tcode{default_delete} object from another \tcode{default_delete} object. \end{itemdescr} \indexlibrarymember{operator()}{default_delete}% \begin{itemdecl} constexpr void operator()(T* ptr) const; \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type. \pnum \effects Calls \keyword{delete} on \tcode{ptr}. \end{itemdescr} \rSec4[unique.ptr.dltr.dflt1]{\tcode{default_delete}} \begin{codeblock} namespace std { template struct default_delete { constexpr default_delete() noexcept = default; template constexpr default_delete(const default_delete&) noexcept; template constexpr void operator()(U* ptr) const; }; } \end{codeblock} \indexlibraryctor{default_delete} \begin{itemdecl} template constexpr default_delete(const default_delete& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{U(*)[]} is convertible to \tcode{T(*)[]}. \pnum \effects Constructs a \tcode{default_delete} object from another \tcode{default_delete} object. \end{itemdescr} \indexlibrarymember{operator()}{default_delete}% \begin{itemdecl} template constexpr void operator()(U* ptr) const; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{U(*)[]} is convertible to \tcode{T(*)[]}. \pnum \mandates \tcode{U} is a complete type. \pnum \effects Calls \tcode{delete[]} on \tcode{ptr}. \end{itemdescr} \rSec3[unique.ptr.single]{\tcode{unique_ptr} for single objects} \rSec4[unique.ptr.single.general]{General} \indexlibraryglobal{unique_ptr}% \begin{codeblock} namespace std { template> class unique_ptr { public: using pointer = @\seebelow@; using element_type = T; using deleter_type = D; // \ref{unique.ptr.single.ctor}, constructors constexpr unique_ptr() noexcept; constexpr explicit unique_ptr(type_identity_t p) noexcept; constexpr unique_ptr(type_identity_t p, @\seebelow@ d1) noexcept; constexpr unique_ptr(type_identity_t p, @\seebelow@ d2) noexcept; constexpr unique_ptr(unique_ptr&& u) noexcept; constexpr unique_ptr(nullptr_t) noexcept; template constexpr unique_ptr(unique_ptr&& u) noexcept; // \ref{unique.ptr.single.dtor}, destructor constexpr ~unique_ptr(); // \ref{unique.ptr.single.asgn}, assignment constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; constexpr unique_ptr& operator=(nullptr_t) noexcept; // \ref{unique.ptr.single.observers}, observers constexpr add_lvalue_reference_t operator*() const noexcept(@\seebelow@); constexpr pointer operator->() const noexcept; constexpr pointer get() const noexcept; constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept; constexpr explicit operator bool() const noexcept; // \ref{unique.ptr.single.modifiers}, modifiers constexpr pointer release() noexcept; constexpr void reset(pointer p = pointer()) noexcept; constexpr void swap(unique_ptr& u) noexcept; // disable copy from lvalue unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; } \end{codeblock} \pnum A program that instantiates the definition of \tcode{unique_ptr} is ill-formed if \tcode{T*} is an invalid type. \begin{note} This prevents the instantiation of specializations such as \tcode{unique_ptr} and \tcode{unique_ptr}. \end{note} \pnum The default type for the template parameter \tcode{D} is \tcode{default_delete}. A client-supplied template argument \tcode{D} shall be a function object type\iref{function.objects}, lvalue reference to function, or lvalue reference to function object type for which, given a value \tcode{d} of type \tcode{D} and a value \tcode{ptr} of type \tcode{unique_ptr::pointer}, the expression \tcode{d(ptr)} is valid and has the effect of disposing of the pointer as appropriate for that deleter. \pnum If the deleter's type \tcode{D} is not a reference type, \tcode{D} shall meet the \oldconceptref{Destructible} requirements (\tref{cpp17.destructible}). \pnum If the \grammarterm{qualified-id} \tcode{remove_reference_t::pointer} is valid and denotes a type\iref{temp.deduct}, then \tcode{unique_ptr::pointer} shall be a synonym for \tcode{remove_reference_t::pointer}. Otherwise \tcode{unique_ptr::pointer} shall be a synonym for \tcode{element_type*}. The type \tcode{unique_ptr::pointer} shall meet the \oldconceptref{NullablePointer} requirements (\tref{cpp17.nullablepointer}). \pnum \begin{example} Given an allocator type \tcode{X}\iref{allocator.requirements.general} and letting \tcode{A} be a synonym for \tcode{allocator_traits}, the types \tcode{A::pointer}, \tcode{A::const_pointer}, \tcode{A::void_pointer}, and \tcode{A::const_void_pointer} may be used as \tcode{unique_ptr::pointer}. \end{example} \rSec4[unique.ptr.single.ctor]{Constructors} \indexlibraryctor{unique_ptr}% \begin{itemdecl} constexpr unique_ptr() noexcept; constexpr unique_ptr(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_pointer_v} is \tcode{false} and \tcode{is_default_constructible_v} is \tcode{true}. \pnum \expects \tcode{D} meets the \oldconceptref{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), and that construction does not throw an exception. \pnum \effects Constructs a \tcode{unique_ptr} object that owns nothing, value-initializing the stored pointer and the stored deleter. \pnum \ensures \tcode{get() == nullptr}. \tcode{get_deleter()} returns a reference to the stored deleter. \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} constexpr explicit unique_ptr(type_identity_t p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_pointer_v} is \tcode{false} and \tcode{is_default_constructible_v} is \tcode{true}. \pnum \expects \tcode{D} meets the \oldconceptref{DefaultConstructible} requirements (\tref{cpp17.defaultconstructible}), and that construction does not throw an exception. \pnum \effects Constructs a \tcode{unique_ptr} which owns \tcode{p}, initializing the stored pointer with \tcode{p} and value-initializing the stored deleter. \pnum \ensures \tcode{get() == p}. \tcode{get_deleter()} returns a reference to the stored deleter. \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} constexpr unique_ptr(type_identity_t p, const D& d) noexcept; constexpr unique_ptr(type_identity_t p, remove_reference_t&& d) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v} is \tcode{true}. \pnum \expects For the first constructor, if \tcode{D} is not a reference type, \tcode{D} meets the \oldconceptref{CopyConstructible} requirements and such construction does not exit via an exception. For the second constructor, if \tcode{D} is not a reference type, \tcode{D} meets the \oldconceptref{MoveConstructible} requirements and such construction does not exit via an exception. \pnum \effects Constructs a \tcode{unique_ptr} object which owns \tcode{p}, initializing the stored pointer with \tcode{p} and initializing the deleter from \tcode{std::forward(d)}. \pnum \ensures \tcode{get() == p}. \tcode{get_deleter()} returns a reference to the stored deleter. If \tcode{D} is a reference type then \tcode{get_deleter()} returns a reference to the lvalue \tcode{d}. \pnum \remarks If \tcode{D} is a reference type, the second constructor is defined as deleted. \pnum \begin{example} \begin{codeblock} D d; unique_ptr p1(new int, D()); // \tcode{D} must be \oldconceptref{MoveConstructible} unique_ptr p2(new int, d); // \tcode{D} must be \oldconceptref{CopyConstructible} unique_ptr p3(new int, d); // \tcode{p3} holds a reference to \tcode{d} unique_ptr p4(new int, D()); // error: rvalue deleter object combined // with reference deleter type \end{codeblock} \end{example} \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} constexpr unique_ptr(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_move_constructible_v} is \tcode{true}. \pnum \expects If \tcode{D} is not a reference type, \tcode{D} meets the \oldconceptref{MoveConstructible} requirements (\tref{cpp17.moveconstructible}). Construction of the deleter from an rvalue of type \tcode{D} does not throw an exception. \pnum \effects Constructs a \tcode{unique_ptr} from \tcode{u}. If \tcode{D} is a reference type, this deleter is copy constructed from \tcode{u}'s deleter; otherwise, this deleter is move constructed from \tcode{u}'s deleter. \begin{note} The construction of the deleter can be implemented with \tcode{std::forward}. \end{note} \pnum \ensures \tcode{get()} yields the value \tcode{u.get()} yielded before the construction. \tcode{u.get() == nullptr}. \tcode{get_deleter()} returns a reference to the stored deleter that was constructed from \tcode{u.get_deleter()}. If \tcode{D} is a reference type then \tcode{get_deleter()} and \tcode{u.get_deleter()} both reference the same lvalue deleter. \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} template constexpr unique_ptr(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, \item \tcode{U} is not an array type, and \item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, or \tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. \end{itemize} \pnum \expects If \tcode{E} is not a reference type, construction of the deleter from an rvalue of type \tcode{E} is well-formed and does not throw an exception. Otherwise, \tcode{E} is a reference type and construction of the deleter from an lvalue of type \tcode{E} is well-formed and does not throw an exception. \pnum \effects Constructs a \tcode{unique_ptr} from \tcode{u}. If \tcode{E} is a reference type, this deleter is copy constructed from \tcode{u}'s deleter; otherwise, this deleter is move constructed from \tcode{u}'s deleter. \begin{note} The deleter constructor can be implemented with \tcode{std::forward}. \end{note} \pnum \ensures \tcode{get()} yields the value \tcode{u.get()} yielded before the construction. \tcode{u.get() == nullptr}. \tcode{get_deleter()} returns a reference to the stored deleter that was constructed from \tcode{u.get_deleter()}. \end{itemdescr} \rSec4[unique.ptr.single.dtor]{Destructor} \indexlibrarydtor{unique_ptr}% \begin{itemdecl} constexpr ~unique_ptr(); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{if (get()) get_deleter()(get());} \begin{note} The use of \tcode{default_delete} requires \tcode{T} to be a complete type. \end{note} \pnum \remarks The behavior is undefined if the evaluation of \tcode{get_deleter()(get())} throws an exception. \end{itemdescr} \rSec4[unique.ptr.single.asgn]{Assignment} \indexlibrarymember{operator=}{unique_ptr}% \begin{itemdecl} constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_move_assignable_v} is \tcode{true}. \pnum \expects If \tcode{D} is not a reference type, \tcode{D} meets the \oldconceptref{MoveAssignable} requirements (\tref{cpp17.moveassignable}) and assignment of the deleter from an rvalue of type \tcode{D} does not throw an exception. Otherwise, \tcode{D} is a reference type; \tcode{remove_reference_t} meets the \oldconceptref{CopyAssignable} requirements and assignment of the deleter from an lvalue of type \tcode{D} does not throw an exception. \pnum \effects Calls \tcode{reset(u.release())} followed by \tcode{get_deleter() = std::forward(u.get_dele\-ter())}. \pnum \ensures If \tcode{this != addressof(u)}, \tcode{u.get() == nullptr}, otherwise \tcode{u.get()} is unchanged. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{unique_ptr}% \begin{itemdecl} template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{pointer}, and \item \tcode{U} is not an array type, and \item \tcode{is_assignable_v} is \tcode{true}. \end{itemize} \pnum \expects If \tcode{E} is not a reference type, assignment of the deleter from an rvalue of type \tcode{E} is well-formed and does not throw an exception. Otherwise, \tcode{E} is a reference type and assignment of the deleter from an lvalue of type \tcode{E} is well-formed and does not throw an exception. \pnum \effects Calls \tcode{reset(u.release())} followed by \tcode{get_deleter() = std::forward(u.get_dele\-ter())}. \pnum \ensures \tcode{u.get() == nullptr}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{unique_ptr}% \begin{itemdecl} constexpr unique_ptr& operator=(nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by \tcode{reset()}. \pnum \ensures \tcode{get() == nullptr}. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec4[unique.ptr.single.observers]{Observers} \indexlibrarymember{operator*}{unique_ptr}% \begin{itemdecl} constexpr add_lvalue_reference_t operator*() const noexcept(noexcept(*declval())); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{*declval()} is a well-formed expression. \pnum \mandates \tcode{reference_converts_from_temporary_v, decltype(\linebreak{}*declval())>} is \tcode{false}. \pnum \expects \tcode{get() != nullptr} is \tcode{true}. \pnum \returns \tcode{*get()}. \end{itemdescr} \indexlibrarymember{operator->}{unique_ptr}% \begin{itemdecl} constexpr pointer operator->() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{get() != nullptr}. \pnum \returns \tcode{get()}. \pnum \begin{note} The use of this function typically requires that \tcode{T} be a complete type. \end{note} \end{itemdescr} \indexlibrarymember{get}{unique_ptr}% \begin{itemdecl} constexpr pointer get() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The stored pointer. \end{itemdescr} \indexlibrarymember{get_deleter}{unique_ptr}% \begin{itemdecl} constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A reference to the stored deleter. \end{itemdescr} \indexlibrarymember{operator bool}{unique_ptr}% \begin{itemdecl} constexpr explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{get() != nullptr}. \end{itemdescr} \rSec4[unique.ptr.single.modifiers]{Modifiers} \indexlibrarymember{release}{unique_ptr}% \begin{itemdecl} constexpr pointer release() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{get() == nullptr}. \pnum \returns The value \tcode{get()} had at the start of the call to \tcode{release}. \end{itemdescr} \indexlibrarymember{reset}{unique_ptr}% \begin{itemdecl} constexpr void reset(pointer p = pointer()) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Assigns \tcode{p} to the stored pointer, and then, with the old value of the stored pointer, \tcode{old_p}, evaluates \tcode{if (old_p) get_deleter()(old_p);} \begin{note} The order of these operations is significant because the call to \tcode{get_deleter()} might destroy \tcode{*this}. \end{note} \pnum \ensures \tcode{get() == p}. \begin{note} The postcondition does not hold if the call to \tcode{get_deleter()} destroys \tcode{*this} since \tcode{this->get()} is no longer a valid expression. \end{note} \pnum \remarks The behavior is undefined if the evaluation of \tcode{get_deleter()(old_p)} throws an exception. \end{itemdescr} \indexlibrarymember{swap}{unique_ptr}% \begin{itemdecl} constexpr void swap(unique_ptr& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{get_deleter()} is swappable\iref{swappable.requirements} and does not throw an exception under \tcode{swap}. \pnum \effects Invokes \tcode{swap} on the stored pointers and on the stored deleters of \tcode{*this} and \tcode{u}. \end{itemdescr} \rSec3[unique.ptr.runtime]{\tcode{unique_ptr} for array objects with a runtime length} \rSec4[unique.ptr.runtime.general]{General} \indexlibraryglobal{unique_ptr}% \begin{codeblock} namespace std { template class unique_ptr { public: using pointer = @\seebelow@; using element_type = T; using deleter_type = D; // \ref{unique.ptr.runtime.ctor}, constructors constexpr unique_ptr() noexcept; template constexpr explicit unique_ptr(U p) noexcept; template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; constexpr unique_ptr(unique_ptr&& u) noexcept; template constexpr unique_ptr(unique_ptr&& u) noexcept; constexpr unique_ptr(nullptr_t) noexcept; // destructor constexpr ~unique_ptr(); // assignment constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; constexpr unique_ptr& operator=(nullptr_t) noexcept; // \ref{unique.ptr.runtime.observers}, observers constexpr T& operator[](size_t i) const; constexpr pointer get() const noexcept; constexpr deleter_type& get_deleter() noexcept; constexpr const deleter_type& get_deleter() const noexcept; constexpr explicit operator bool() const noexcept; // \ref{unique.ptr.runtime.modifiers}, modifiers constexpr pointer release() noexcept; template constexpr void reset(U p) noexcept; constexpr void reset(nullptr_t = nullptr) noexcept; constexpr void swap(unique_ptr& u) noexcept; // disable copy from lvalue unique_ptr(const unique_ptr&) = delete; unique_ptr& operator=(const unique_ptr&) = delete; }; } \end{codeblock} \pnum A specialization for array types is provided with a slightly altered interface. \begin{itemize} \item Conversions between different types of \tcode{unique_ptr} that would be disallowed for the corresponding pointer-to-array types, and conversions to or from the non-array forms of \tcode{unique_ptr}, produce an ill-formed program. \item Pointers to types derived from \tcode{T} are rejected by the constructors, and by \tcode{reset}. \item The observers \tcode{operator*} and \tcode{operator->} are not provided. \item The indexing observer \tcode{operator[]} is provided. \item The default deleter will call \tcode{delete[]}. \end{itemize} \pnum Descriptions are provided below only for members that differ from the primary template. \pnum The template argument \tcode{T} shall be a complete type. \rSec4[unique.ptr.runtime.ctor]{Constructors} \indexlibraryctor{unique_ptr}% \begin{itemdecl} template constexpr explicit unique_ptr(U p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum This constructor behaves the same as the constructor in the primary template that takes a single parameter of type \tcode{pointer}. \pnum \constraints \begin{itemize} \item \tcode{U} is the same type as \tcode{pointer}, or \item \tcode{pointer} is the same type as \tcode{element_type*}, \tcode{U} is a pointer type \tcode{V*}, and \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. \end{itemize} \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; template constexpr unique_ptr(U p, @\seebelow@ d) noexcept; \end{itemdecl} \begin{itemdescr} \pnum These constructors behave the same as the constructors in the primary template that take a parameter of type \tcode{pointer} and a second parameter. \pnum \constraints \begin{itemize} \item \tcode{U} is the same type as \tcode{pointer}, \item \tcode{U} is \tcode{nullptr_t}, or \item \tcode{pointer} is the same type as \tcode{element_type*}, \tcode{U} is a pointer type \tcode{V*}, and \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. \end{itemize} \end{itemdescr} \indexlibraryctor{unique_ptr}% \begin{itemdecl} template constexpr unique_ptr(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum This constructor behaves the same as in the primary template. \pnum \constraints Where \tcode{UP} is \tcode{unique_ptr}: \begin{itemize} \item \tcode{U} is an array type, and \item \tcode{pointer} is the same type as \tcode{element_type*}, and \item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and \item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and \item either \tcode{D} is a reference type and \tcode{E} is the same type as \tcode{D}, or \tcode{D} is not a reference type and \tcode{E} is implicitly convertible to \tcode{D}. \end{itemize} \begin{note} This replaces the \constraints specification of the primary template. \end{note} \end{itemdescr} \rSec4[unique.ptr.runtime.asgn]{Assignment} \indexlibrarymember{operator=}{unique_ptr}% \begin{itemdecl} template constexpr unique_ptr& operator=(unique_ptr&& u) noexcept; \end{itemdecl} \begin{itemdescr} \pnum This operator behaves the same as in the primary template. \pnum \constraints Where \tcode{UP} is \tcode{unique_ptr}: \begin{itemize} \item \tcode{U} is an array type, and \item \tcode{pointer} is the same type as \tcode{element_type*}, and \item \tcode{UP::pointer} is the same type as \tcode{UP::element_type*}, and \item \tcode{UP::element_type(*)[]} is convertible to \tcode{element_type(*)[]}, and \item \tcode{is_assignable_v} is \tcode{true}. \end{itemize} \begin{note} This replaces the \constraints specification of the primary template. \end{note} \end{itemdescr} \rSec4[unique.ptr.runtime.observers]{Observers} \indexlibrarymember{operator[]}{unique_ptr}% \begin{itemdecl} constexpr T& operator[](size_t i) const; \end{itemdecl} \begin{itemdescr} \pnum \expects $\tcode{i} <$ the number of elements in the array to which the stored pointer points. \pnum \returns \tcode{get()[i]}. \end{itemdescr} \rSec4[unique.ptr.runtime.modifiers]{Modifiers} \indexlibrarymember{reset}{unique_ptr}% \begin{itemdecl} constexpr void reset(nullptr_t p = nullptr) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{reset(pointer())}. \end{itemdescr} \indexlibrarymember{reset}{unique_ptr}% \begin{itemdecl} template constexpr void reset(U p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum This function behaves the same as the \tcode{reset} member of the primary template. \pnum \constraints \begin{itemize} \item \tcode{U} is the same type as \tcode{pointer}, or \item \tcode{pointer} is the same type as \tcode{element_type*}, \tcode{U} is a pointer type \tcode{V*}, and \tcode{V(*)[]} is convertible to \tcode{element_type(*)[]}. \end{itemize} \end{itemdescr} \rSec3[unique.ptr.create]{Creation} \indexlibraryglobal{make_unique}% \begin{itemdecl} template constexpr unique_ptr make_unique(Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is not an array type. \pnum \returns \tcode{unique_ptr(new T(std::forward(args)...))}. \end{itemdescr} \indexlibraryglobal{make_unique}% \begin{itemdecl} template constexpr unique_ptr make_unique(size_t n); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of unknown bound. \pnum \returns \tcode{unique_ptr(new remove_extent_t[n]())}. \end{itemdescr} \indexlibraryglobal{make_unique}% \begin{itemdecl} template @\unspec@ make_unique(Args&&...) = delete; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of known bound. \end{itemdescr} \indexlibraryglobal{make_unique}% \begin{itemdecl} template constexpr unique_ptr make_unique_for_overwrite(); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is not an array type. \pnum \returns \tcode{unique_ptr(new T)}. \end{itemdescr} \indexlibraryglobal{make_unique}% \begin{itemdecl} template constexpr unique_ptr make_unique_for_overwrite(size_t n); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of unknown bound. \pnum \returns \tcode{unique_ptr(new remove_extent_t[n])}. \end{itemdescr} \indexlibraryglobal{make_unique}% \begin{itemdecl} template @\unspec@ make_unique_for_overwrite(Args&&...) = delete; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of known bound. \end{itemdescr} \rSec3[unique.ptr.special]{Specialized algorithms} \indexlibrary{\idxcode{swap(unique_ptr\&, unique_ptr\&)}}% \begin{itemdecl} template constexpr void swap(unique_ptr& x, unique_ptr& y) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_swappable_v} is \tcode{true}. \pnum \effects Calls \tcode{x.swap(y)}. \end{itemdescr} \indexlibrarymember{operator==}{unique_ptr}% \begin{itemdecl} template constexpr bool operator==(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{x.get() == y.get()}. \end{itemdescr} \indexlibrarymember{operator<}{unique_ptr}% \begin{itemdecl} template constexpr bool operator<(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{CT} denote \begin{codeblock} common_type_t::pointer, typename unique_ptr::pointer> \end{codeblock} \pnum \mandates \begin{itemize} \item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT} and \item \tcode{unique_ptr::pointer} is implicitly convertible to \tcode{CT}. \end{itemize} \pnum \expects The specialization \tcode{less} is a function object type\iref{function.objects} that induces a strict weak ordering\iref{alg.sorting} on the pointer values. \pnum \returns \tcode{less()(x.get(), y.get())}. \end{itemdescr} \indexlibrarymember{operator>}{unique_ptr}% \begin{itemdecl} template constexpr bool operator>(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{y < x}. \end{itemdescr} \indexlibrarymember{operator<=}{unique_ptr}% \begin{itemdecl} template constexpr bool operator<=(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{!(y < x)}. \end{itemdescr} \indexlibrarymember{operator>=}{unique_ptr}% \begin{itemdecl} template constexpr bool operator>=(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{!(x < y)}. \end{itemdescr} \indexlibrarymember{operator<=>}{unique_ptr}% \begin{itemdecl} template requires @\libconcept{three_way_comparable_with}@::pointer, typename unique_ptr::pointer> constexpr compare_three_way_result_t::pointer, typename unique_ptr::pointer> operator<=>(const unique_ptr& x, const unique_ptr& y); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{compare_three_way()(x.get(), y.get())}. \end{itemdescr} \indexlibrarymember{operator==}{unique_ptr}% \begin{itemdecl} template constexpr bool operator==(const unique_ptr& x, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{!x}. \end{itemdescr} \indexlibrarymember{operator<}{unique_ptr}% \begin{itemdecl} template constexpr bool operator<(const unique_ptr& x, nullptr_t); template constexpr bool operator<(nullptr_t, const unique_ptr& x); \end{itemdecl} \begin{itemdescr} \pnum \expects The specialization \tcode{less::pointer>} is a function object type\iref{function.objects} that induces a strict weak ordering\iref{alg.sorting} on the pointer values. \pnum \returns The first function template returns \begin{codeblock} less::pointer>()(x.get(), nullptr) \end{codeblock} The second function template returns \begin{codeblock} less::pointer>()(nullptr, x.get()) \end{codeblock} \end{itemdescr} \indexlibrarymember{operator>}{unique_ptr}% \begin{itemdecl} template constexpr bool operator>(const unique_ptr& x, nullptr_t); template constexpr bool operator>(nullptr_t, const unique_ptr& x); \end{itemdecl} \begin{itemdescr} \pnum \returns The first function template returns \tcode{nullptr < x}. The second function template returns \tcode{x < nullptr}. \end{itemdescr} \indexlibrarymember{operator<=}{unique_ptr}% \begin{itemdecl} template constexpr bool operator<=(const unique_ptr& x, nullptr_t); template constexpr bool operator<=(nullptr_t, const unique_ptr& x); \end{itemdecl} \begin{itemdescr} \pnum \returns The first function template returns \tcode{!(nullptr < x)}. The second function template returns \tcode{!(x < nullptr)}. \end{itemdescr} \indexlibrarymember{operator>=}{unique_ptr}% \begin{itemdecl} template constexpr bool operator>=(const unique_ptr& x, nullptr_t); template constexpr bool operator>=(nullptr_t, const unique_ptr& x); \end{itemdecl} \begin{itemdescr} \pnum \returns The first function template returns \tcode{!(x < nullptr)}. The second function template returns \tcode{!(nullptr < x)}. \end{itemdescr} \indexlibrarymember{operator<=>}{unique_ptr}% \begin{itemdecl} template requires @\libconcept{three_way_comparable}@::pointer> constexpr compare_three_way_result_t::pointer> operator<=>(const unique_ptr& x, nullptr_t); \end{itemdecl} \begin{itemdescr} \pnum \returns \begin{codeblock} compare_three_way()(x.get(), static_cast::pointer>(nullptr)). \end{codeblock} \end{itemdescr} \rSec3[unique.ptr.io]{I/O} \indexlibrarymember{operator<<}{unique_ptr}% \begin{itemdecl} template basic_ostream& operator<<(basic_ostream& os, const unique_ptr& p); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{os << p.get()} is a valid expression. \pnum \effects Equivalent to: \tcode{os << p.get();} \pnum \returns \tcode{os}. \end{itemdescr} \rSec2[util.sharedptr]{Shared-ownership pointers} \rSec3[util.smartptr.weak.bad]{Class \tcode{bad_weak_ptr}}% \indextext{smart pointers|(}% \indexlibraryglobal{bad_weak_ptr}% \begin{codeblock} namespace std { class bad_weak_ptr : public exception { public: // see \ref{exception} for the specification of the special member functions constexpr const char* what() const noexcept override; }; } \end{codeblock} \pnum An exception of type \tcode{bad_weak_ptr} is thrown by the \tcode{shared_ptr} constructor taking a \tcode{weak_ptr}. \indexlibrarymember{what}{bad_weak_ptr}% \begin{itemdecl} constexpr const char* what() const noexcept override; \end{itemdecl} \begin{itemdescr} \pnum \returns An \impldef{return value of \tcode{bad_weak_ptr::what}} \ntbs{}. \end{itemdescr} \rSec3[util.smartptr.shared]{Class template \tcode{shared_ptr}} \rSec4[util.smartptr.shared.general]{General} \pnum \indexlibraryglobal{shared_ptr}% The \tcode{shared_ptr} class template stores a pointer, usually obtained via \keyword{new}. \tcode{shared_ptr} implements semantics of shared ownership; the last remaining owner of the pointer is responsible for destroying the object, or otherwise releasing the resources associated with the stored pointer. A \tcode{shared_ptr} is said to be empty if it does not own a pointer. \begin{codeblock} namespace std { template class shared_ptr { public: using element_type = remove_extent_t; using weak_type = weak_ptr; // \ref{util.smartptr.shared.const}, constructors constexpr shared_ptr() noexcept; constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { } template constexpr explicit shared_ptr(Y* p); template constexpr shared_ptr(Y* p, D d); template constexpr shared_ptr(Y* p, D d, A a); template constexpr shared_ptr(nullptr_t p, D d); template constexpr shared_ptr(nullptr_t p, D d, A a); template constexpr shared_ptr(const shared_ptr& r, element_type* p) noexcept; template constexpr shared_ptr(shared_ptr&& r, element_type* p) noexcept; constexpr shared_ptr(const shared_ptr& r) noexcept; template constexpr shared_ptr(const shared_ptr& r) noexcept; constexpr shared_ptr(shared_ptr&& r) noexcept; template constexpr shared_ptr(shared_ptr&& r) noexcept; template constexpr explicit shared_ptr(const weak_ptr& r); template constexpr shared_ptr(unique_ptr&& r); // \ref{util.smartptr.shared.dest}, destructor constexpr ~shared_ptr(); // \ref{util.smartptr.shared.assign}, assignment constexpr shared_ptr& operator=(const shared_ptr& r) noexcept; template constexpr shared_ptr& operator=(const shared_ptr& r) noexcept; constexpr shared_ptr& operator=(shared_ptr&& r) noexcept; template constexpr shared_ptr& operator=(shared_ptr&& r) noexcept; template constexpr shared_ptr& operator=(unique_ptr&& r); // \ref{util.smartptr.shared.mod}, modifiers constexpr void swap(shared_ptr& r) noexcept; constexpr void reset() noexcept; template constexpr void reset(Y* p); template constexpr void reset(Y* p, D d); template constexpr void reset(Y* p, D d, A a); // \ref{util.smartptr.shared.obs}, observers constexpr element_type* get() const noexcept; constexpr T& operator*() const noexcept; constexpr T* operator->() const noexcept; constexpr element_type& operator[](ptrdiff_t i) const; constexpr long use_count() const noexcept; constexpr explicit operator bool() const noexcept; template bool owner_before(const shared_ptr& b) const noexcept; template bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; template constexpr bool owner_equal(const weak_ptr& b) const noexcept; }; template shared_ptr(weak_ptr) -> shared_ptr; template shared_ptr(unique_ptr) -> shared_ptr; } \end{codeblock} \pnum Specializations of \tcode{shared_ptr} shall be \oldconceptref{CopyConstructible}, \oldconceptref{CopyAssignable}, and \oldconceptref{LessThanComparable}, allowing their use in standard containers. Specializations of \tcode{shared_ptr} shall be contextually convertible to \tcode{bool}, allowing their use in boolean expressions and declarations in conditions. \pnum The template parameter \tcode{T} of \tcode{shared_ptr} may be an incomplete type. \begin{note} \tcode{T} can be a function type. \end{note} \pnum \begin{example} \begin{codeblock} if (shared_ptr px = dynamic_pointer_cast(py)) { // do something with \tcode{px} } \end{codeblock} \end{example} \pnum For purposes of determining the presence of a data race, member functions shall access and modify only the \tcode{shared_ptr} and \tcode{weak_ptr} objects themselves and not objects they refer to. Changes in \tcode{use_count()} do not reflect modifications that can introduce data races. \pnum For the purposes of \ref{smartptr}, a pointer type \tcode{Y*} is said to be \defnx{compatible with}{compatible with!\idxcode{shared_ptr}} a pointer type \tcode{T*} when either \tcode{Y*} is convertible to \tcode{T*} or \tcode{Y} is \tcode{U[N]} and \tcode{T} is \cv{}~\tcode{U[]}. \rSec4[util.smartptr.shared.const]{Constructors} \pnum In the constructor definitions below, enables \tcode{shared_from_this} with \tcode{p}, for a pointer \tcode{p} of type \tcode{Y*}, means that if \tcode{Y} has an unambiguous and accessible base class that is a specialization of \tcode{enable_shared_from_this}\iref{util.smartptr.enab}, then \tcode{remove_cv_t*} shall be implicitly convertible to \tcode{T*} and the constructor evaluates the statement: \begin{codeblock} if (p != nullptr && p->@\exposid{weak-this}@.expired()) p->@\exposid{weak-this}@ = shared_ptr>(*this, const_cast*>(p)); \end{codeblock} The assignment to the \exposid{weak-this} member is not atomic and conflicts with any potentially concurrent access to the same object\iref{intro.multithread}. \indexlibraryctor{shared_ptr}% \begin{itemdecl} constexpr shared_ptr() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \ensures \tcode{use_count() == 0 \&\& get() == nullptr}. \end{itemdescr} \indexlibraryctor{shared_ptr}% \begin{itemdecl} template constexpr explicit shared_ptr(Y* p); \end{itemdecl} \begin{itemdescr} \pnum \constraints When \tcode{T} is an array type, the expression \tcode{delete[] p} is well-formed and either \tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or \tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. When \tcode{T} is not an array type, the expression \tcode{delete p} is well-formed and \tcode{Y*} is convertible to \tcode{T*}. \pnum \mandates \tcode{Y} is a complete type. \pnum \expects The expression \tcode{delete[] p}, when \tcode{T} is an array type, or \tcode{delete p}, when \tcode{T} is not an array type, has well-defined behavior, and does not throw exceptions. \pnum \effects When \tcode{T} is not an array type, constructs a \tcode{shared_ptr} object that owns the pointer \tcode{p}. Otherwise, constructs a \tcode{shared_ptr} that owns \tcode{p} and a deleter of an unspecified type that calls \tcode{delete[] p}. When \tcode{T} is not an array type, enables \tcode{shared_from_this} with \tcode{p}. If an exception is thrown, \tcode{delete p} is called when \tcode{T} is not an array type, \tcode{delete[] p} otherwise. \pnum \ensures \tcode{use_count() == 1 \&\& get() == p}. \pnum \throws \tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} constructor fails} exception when a resource other than memory cannot be obtained. \end{itemdescr} \indexlibraryctor{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr(Y* p, D d); template constexpr shared_ptr(Y* p, D d, A a); template constexpr shared_ptr(nullptr_t p, D d); template constexpr shared_ptr(nullptr_t p, D d, A a); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_move_constructible_v} is \tcode{true}, and \tcode{d(p)} is a well-formed expression. For the first two overloads: \begin{itemize} \item If \tcode{T} is an array type, then either \tcode{T} is \tcode{U[N]} and \tcode{Y(*)[N]} is convertible to \tcode{T*}, or \tcode{T} is \tcode{U[]} and \tcode{Y(*)[]} is convertible to \tcode{T*}. \item If \tcode{T} is not an array type, then \tcode{Y*} is convertible to \tcode{T*}. \end{itemize} \pnum \expects Construction of \tcode{d} and a deleter of type \tcode{D} initialized with \tcode{std::move(d)} do not throw exceptions. The expression \tcode{d(p)} has well-defined behavior and does not throw exceptions. \tcode{A} meets the \oldconceptref{Allocator} requirements\iref{allocator.requirements.general}. \pnum \effects Constructs a \tcode{shared_ptr} object that owns the object \tcode{p} and the deleter \tcode{d}. When \tcode{T} is not an array type, the first and second constructors enable \tcode{shared_from_this} with \tcode{p}. The second and fourth constructors shall use a copy of \tcode{a} to allocate memory for internal use. If an exception is thrown, \tcode{d(p)} is called. \pnum \ensures \tcode{use_count() == 1 \&\& get() == p}. \pnum \throws \tcode{bad_alloc}, or an \impldef{exception type when \tcode{shared_ptr} constructor fails} exception when a resource other than memory cannot be obtained. \end{itemdescr} \indexlibraryctor{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr(const shared_ptr& r, element_type* p) noexcept; template constexpr shared_ptr(shared_ptr&& r, element_type* p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Constructs a \tcode{shared_ptr} instance that stores \tcode{p} and shares ownership with the initial value of \tcode{r}. \pnum \ensures \tcode{get() == p}. For the second overload, \tcode{r} is empty and \tcode{r.get() == nullptr}. \pnum \begin{note} Use of this constructor leads to a dangling pointer unless \tcode{p} remains valid at least until the ownership group of \tcode{r} is destroyed. \end{note} \pnum \begin{note} This constructor allows creation of an empty \tcode{shared_ptr} instance with a non-null stored pointer. \end{note} \end{itemdescr} \indexlibraryctor{shared_ptr}% \begin{itemdecl} constexpr shared_ptr(const shared_ptr& r) noexcept; template constexpr shared_ptr(const shared_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. \pnum \effects If \tcode{r} is empty, constructs an empty \tcode{shared_ptr} object; otherwise, constructs a \tcode{shared_ptr} object that shares ownership with \tcode{r}. \pnum \ensures \tcode{get() == r.get() \&\& use_count() == r.use_count()}. \end{itemdescr} \indexlibraryctor{shared_ptr}% \begin{itemdecl} constexpr shared_ptr(shared_ptr&& r) noexcept; template constexpr shared_ptr(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. \pnum \effects Move constructs a \tcode{shared_ptr} instance from \tcode{r}. \pnum \ensures \tcode{*this} contains the old value of \tcode{r}. \tcode{r} is empty, and \tcode{r.get() == nullptr}. \end{itemdescr} \indexlibraryctor{shared_ptr}% \indexlibraryglobal{weak_ptr}% \begin{itemdecl} template constexpr explicit shared_ptr(const weak_ptr& r); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{Y*} is compatible with \tcode{T*}. \pnum \effects Constructs a \tcode{shared_ptr} object that shares ownership with \tcode{r} and stores a copy of the pointer stored in \tcode{r}. If an exception is thrown, the constructor has no effect. \pnum \ensures \tcode{use_count() == r.use_count()}. \pnum \throws \tcode{bad_weak_ptr} when \tcode{r.expired()}. \end{itemdescr} \indexlibraryctor{shared_ptr}% \indexlibraryglobal{unique_ptr}% \begin{itemdecl} template constexpr shared_ptr(unique_ptr&& r); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{Y*} is compatible with \tcode{T*} and \tcode{unique_ptr::pointer} is convertible to \tcode{element_type*}. \pnum \effects If \tcode{r.get() == nullptr}, equivalent to \tcode{shared_ptr()}. Otherwise, if \tcode{D} is not a reference type, equivalent to \tcode{shared_ptr(r.release(), std::move(r.get_deleter()))}. Otherwise, equivalent to \tcode{shared_ptr(r.release(), ref(r.get_deleter()))}. If an exception is thrown, the constructor has no effect. \end{itemdescr} \rSec4[util.smartptr.shared.dest]{Destructor} \indexlibrarydtor{shared_ptr}% \begin{itemdecl} constexpr ~shared_ptr(); \end{itemdecl} \begin{itemdescr} \pnum \effects \begin{itemize} \item If \tcode{*this} is empty or shares ownership with another \tcode{shared_ptr} instance (\tcode{use_count() > 1}), there are no side effects. \item Otherwise, if \tcode{*this} owns an object \tcode{p} and a deleter \tcode{d}, \tcode{d(p)} is called. \item Otherwise, \tcode{*this} owns a pointer \tcode{p}, and \tcode{delete p} is called. \end{itemize} \end{itemdescr} \pnum \begin{note} Since the destruction of \tcode{*this} decreases the number of instances that share ownership with \tcode{*this} by one, after \tcode{*this} has been destroyed all \tcode{shared_ptr} instances that shared ownership with \tcode{*this} will report a \tcode{use_count()} that is one less than its previous value. \end{note} \rSec4[util.smartptr.shared.assign]{Assignment} \indexlibrarymember{operator=}{shared_ptr}% \begin{itemdecl} constexpr shared_ptr& operator=(const shared_ptr& r) noexcept; template constexpr shared_ptr& operator=(const shared_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(r).swap(*this)}. \pnum \returns \tcode{*this}. \pnum \begin{note} The use count updates caused by the temporary object construction and destruction are not observable side effects, so the implementation can meet the effects (and the implied guarantees) via different means, without creating a temporary. In particular, in the example: \begin{codeblock} shared_ptr p(new int); shared_ptr q(p); p = p; q = p; \end{codeblock} both assignments can be no-ops. \end{note} \end{itemdescr} \indexlibrarymember{operator=}{shared_ptr}% \begin{itemdecl} constexpr shared_ptr& operator=(shared_ptr&& r) noexcept; template constexpr shared_ptr& operator=(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr& operator=(unique_ptr&& r); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(std::move(r)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec4[util.smartptr.shared.mod]{Modifiers} \indexlibrarymember{swap}{shared_ptr}% \begin{itemdecl} constexpr void swap(shared_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the contents of \tcode{*this} and \tcode{r}. \end{itemdescr} \indexlibrarymember{reset}{shared_ptr}% \begin{itemdecl} constexpr void reset() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr().swap(*this)}. \end{itemdescr} \indexlibrarymember{reset}{shared_ptr}% \begin{itemdecl} template constexpr void reset(Y* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(p).swap(*this)}. \end{itemdescr} \indexlibrarymember{reset}{shared_ptr}% \begin{itemdecl} template constexpr void reset(Y* p, D d); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(p, d).swap(*this)}. \end{itemdescr} \indexlibrarymember{reset}{shared_ptr}% \begin{itemdecl} template constexpr void reset(Y* p, D d, A a); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{shared_ptr(p, d, a).swap(*this)}. \end{itemdescr} \rSec4[util.smartptr.shared.obs]{Observers} \indexlibrarymember{get}{shared_ptr}% \begin{itemdecl} constexpr element_type* get() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The stored pointer. \end{itemdescr} \indexlibrarymember{operator*}{shared_ptr}% \begin{itemdecl} constexpr T& operator*() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{get() != nullptr}. \pnum \returns \tcode{*get()}. \pnum \remarks When \tcode{T} is an array type or \cv{}~\keyword{void}, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed. \end{itemdescr} \indexlibrarymember{operator->}{shared_ptr}% \begin{itemdecl} constexpr T* operator->() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{get() != nullptr}. \pnum \returns \tcode{get()}. \pnum \remarks When \tcode{T} is an array type, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed. \end{itemdescr} \indexlibrarymember{operator[]}{shared_ptr}% \begin{itemdecl} constexpr element_type& operator[](ptrdiff_t i) const; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{get() != nullptr} is \tcode{true}. \pnum \hardexpects $\tcode{i} \ge 0$. If \tcode{T} is \tcode{U[N]}, $\tcode{i} < \tcode{N}$. \pnum \returns \tcode{get()[i]}. \pnum \throws Nothing. \pnum \remarks When \tcode{T} is not an array type, it is unspecified whether this member function is declared. If it is declared, it is unspecified what its return type is, except that the declaration (although not necessarily the definition) of the function shall be well-formed. \end{itemdescr} \indexlibrarymember{use_count}{shared_ptr}% \begin{itemdecl} constexpr long use_count() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \sync None. \pnum \returns The number of \tcode{shared_ptr} objects, \tcode{*this} included, that share ownership with \tcode{*this}, or \tcode{0} when \tcode{*this} is empty. \pnum \begin{note} \tcode{get() == nullptr} does not imply a specific return value of \tcode{use_count()}. \end{note} \pnum \begin{note} \tcode{weak_ptr::lock()} can affect the return value of \tcode{use_count()}. \end{note} \pnum \begin{note} When multiple threads might affect the return value of \tcode{use_count()}, the result is approximate. In particular, \tcode{use_count() == 1} does not imply that accesses through a previously destroyed \tcode{shared_ptr} have in any sense completed. \end{note} \end{itemdescr} \indexlibrarymember{operator bool}{shared_ptr}% \begin{itemdecl} constexpr explicit operator bool() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{get() != nullptr}. \end{itemdescr} \indexlibrarymember{owner_before}{shared_ptr}% \begin{itemdecl} template bool owner_before(const shared_ptr& b) const noexcept; template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An unspecified value such that \begin{itemize} \item \tcode{owner_before(b)} defines a strict weak ordering as defined in~\ref{alg.sorting}; \item \tcode{!owner_before(b) \&\& !b.owner_before(*this)} is \tcode{true} if and only if \tcode{owner_equal(b)} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{owner_hash}{shared_ptr}% \begin{itemdecl} size_t owner_hash() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An unspecified value such that, for any object \tcode{x} where \tcode{owner_equal(x)} is \tcode{true}, \tcode{owner_hash() == x.owner_hash()} is \tcode{true}. \end{itemdescr} \indexlibrarymember{owner_equal}{shared_ptr}% \begin{itemdecl} template constexpr bool owner_equal(const shared_ptr& b) const noexcept; template constexpr bool owner_equal(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if and only if \tcode{*this} and \tcode{b} share ownership or are both empty. Otherwise returns \tcode{false}. \pnum \remarks \tcode{owner_equal} is an equivalence relation. \end{itemdescr} \rSec4[util.smartptr.shared.create]{Creation} \pnum The common requirements that apply to all \tcode{make_shared}, \tcode{allocate_shared}, \tcode{make_shared_for_overwrite}, and \tcode{allocate_shared_for_overwrite} overloads, unless specified otherwise, are described below. \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(@\placeholdernc{args}@); template constexpr shared_ptr allocate_shared(const A& a, @\placeholdernc{args}@); template constexpr shared_ptr make_shared_for_overwrite(@\placeholdernc{args}@); template constexpr shared_ptr allocate_shared_for_overwrite(const A& a, @\placeholdernc{args}@); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{A} meets the \oldconceptref{Allocator} requirements\iref{allocator.requirements.general}. \pnum \effects Allocates memory for an object of type \tcode{T} (or \tcode{U[N]} when \tcode{T} is \tcode{U[]}, where \tcode{N} is determined from \placeholder{args} as specified by the concrete overload). The object is initialized from \placeholder{args} as specified by the concrete overload. The \tcode{allocate_shared} and \tcode{allocate_shared_for_overwrite} templates use a copy of \tcode{a} (rebound for an unspecified \tcode{value_type}) to allocate memory. If an exception is thrown, the functions have no effect. \pnum \ensures \tcode{r.get() != nullptr \&\& r.use_count() == 1}, where \tcode{r} is the return value. \pnum \returns A \tcode{shared_ptr} instance that stores and owns the address of the newly constructed object. \pnum \throws \tcode{bad_alloc}, or an exception thrown from \tcode{allocate} or from the initialization of the object. \pnum \remarks \begin{itemize} \item Implementations should perform no more than one memory allocation. \begin{note} This provides efficiency equivalent to an intrusive smart pointer. \end{note} \item When an object of an array type \tcode{U} is specified to have an initial value of \tcode{u} (of the same type), this shall be interpreted to mean that each array element of the object has as its initial value the corresponding element from \tcode{u}. \item When an object of an array type is specified to have a default initial value, this shall be interpreted to mean that each array element of the object has a default initial value. \item When a (sub)object of a non-array type \tcode{U} is specified to have an initial value of \tcode{v}, or \tcode{U(l...)}, where \tcode{l...} is a list of constructor arguments, \tcode{make_shared} shall initialize this (sub)object via the expression \tcode{::new(pv) U(v)} or \tcode{::new(pv) U(l...)} respectively, where \tcode{pv} has type \tcode{void*} and points to storage suitable to hold an object of type \tcode{U}. \item When a (sub)object of a non-array type \tcode{U} is specified to have an initial value of \tcode{v}, or \tcode{U(l...)}, where \tcode{l...} is a list of constructor arguments, \tcode{allocate_shared} shall initialize this (sub)object via the expression \begin{itemize} \item \tcode{allocator_traits::construct(a2, pu, v)} or \item \tcode{allocator_traits::construct(a2, pu, l...)} \end{itemize} respectively, where \tcode{pu} is a pointer of type \tcode{remove_cv_t*} pointing to storage suitable to hold an object of type \tcode{remove_cv_t} and \tcode{a2} of type \tcode{A2} is a potentially rebound copy of the allocator \tcode{a} passed to \tcode{allocate_shared}. \item When a (sub)object of non-array type \tcode{U} is specified to have a default initial value, \tcode{make_shared} shall initialize this (sub)object via the expression \tcode{::new(pv) U()}, where \tcode{pv} has type \tcode{void*} and points to storage suitable to hold an object of type \tcode{U}. \item When a (sub)object of non-array type \tcode{U} is specified to have a default initial value, \tcode{allocate_shared} initializes this (sub)object via the expression \tcode{allocator_traits::construct(a2, pu)}, where \tcode{pu} is a pointer of type \tcode{remove_cv_t*} pointing to storage suitable to hold an object of type \tcode{remove_cv_t} and \tcode{a2} of type \tcode{A2} is a potentially rebound copy of the allocator \tcode{a} passed to \tcode{allocate_shared}. \item When a (sub)object of non-array type \tcode{U} is initialized by \tcode{make_shared_for_overwrite} or \tcode{allocate_shared_for_overwrite}, it is initialized via the expression \tcode{::new(pv) U}, where \tcode{pv} has type \tcode{void*} and points to storage suitable to hold an object of type \tcode{U}. \item Array elements are initialized in ascending order of their addresses. \item When the lifetime of the object managed by the return value ends, or when the initialization of an array element throws an exception, the initialized elements are destroyed in the reverse order of their original construction. \item When a (sub)object of non-array type \tcode{U} that was initialized by \tcode{make_shared}, \tcode{make_shared_for_overwrite}, or \tcode{allocate_shared_for_overwrite} is to be destroyed, it is destroyed via the expression \tcode{pu->\~{}U()} where \tcode{pu} points to that object of type \tcode{U}. \item When a (sub)object of non-array type \tcode{U} that was initialized by \tcode{allocate_shared} is to be destroyed, it is destroyed via the expression \tcode{allocator_traits::destroy(a2, pu)} where \tcode{pu} is a pointer of type \tcode{remove_cv_t*} pointing to that object of type \tcode{remove_cv_t} and \tcode{a2} of type \tcode{A2} is a potentially rebound copy of the allocator \tcode{a} passed to \tcode{allocate_shared}. \end{itemize} \begin{note} These functions will typically allocate more memory than \tcode{sizeof(T)} to allow for internal bookkeeping structures such as reference counts. \end{note} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(Args&&... args); // \tcode{T} is not array template constexpr shared_ptr allocate_shared(const A& a, Args&&... args); // \tcode{T} is not array \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is not an array type. \pnum \returns A \tcode{shared_ptr} to an object of type \tcode{T} with an initial value \tcode{T(std::forward(args)...)}. \pnum \remarks The \tcode{shared_ptr} constructors called by these functions enable \tcode{shared_from_this} with the address of the newly constructed object of type \tcode{T}. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared(); // \tcode{shared_ptr} to \tcode{int()} shared_ptr> q = make_shared>(16, 1); // \tcode{shared_ptr} to vector of \tcode{16} elements with value \tcode{1} \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(size_t N); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr allocate_shared(const A& a, size_t N); // \tcode{T} is \tcode{U[]} \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of unknown bound. \pnum \returns A \tcode{shared_ptr} to an array of \tcode{N} elements of type \tcode{remove_extent_t} with a default initial value. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared(1024); // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} shared_ptr q = make_shared(6); // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(); // \tcode{T} is \tcode{U[N]} template constexpr shared_ptr allocate_shared(const A& a); // \tcode{T} is \tcode{U[N]} \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of known bound. \pnum \returns A \tcode{shared_ptr} to an object of type \tcode{T} with a default initial value. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared(); // \tcode{shared_ptr} to a value-initialized \tcode{double[1024]} shared_ptr q = make_shared(); // \tcode{shared_ptr} to a value-initialized \tcode{double[6][2][2]} \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} template constexpr shared_ptr allocate_shared(const A& a, size_t N, const remove_extent_t& u); // \tcode{T} is \tcode{U[]} \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of unknown bound. \pnum \returns A \tcode{shared_ptr} to an array of \tcode{N} elements of type \tcode{remove_extent_t} where each array element has an initial value of \tcode{u}. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared(1024, 1.0); // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} shared_ptr q = make_shared(6, {1.0, 0.0}); // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{double[2]} element is \tcode{\{1.0, 0.0\}} shared_ptr[]> r = make_shared[]>(4, {1, 2}); // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared(const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} template constexpr shared_ptr allocate_shared(const A& a, const remove_extent_t& u); // \tcode{T} is \tcode{U[N]} \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of known bound. \pnum \returns A \tcode{shared_ptr} to an object of type \tcode{T}, where each array element of type \tcode{remove_extent_t} has an initial value of \tcode{u}. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared(1.0); // \tcode{shared_ptr} to a \tcode{double[1024]}, where each element is \tcode{1.0} shared_ptr q = make_shared({1.0, 0.0}); // \tcode{shared_ptr} to a \tcode{double[6][2]}, where each \tcode{double[2]} element is \tcode{\{1.0, 0.0\}} shared_ptr[4]> r = make_shared[4]>({1, 2}); // \tcode{shared_ptr} to a \tcode{vector[4]}, where each vector has contents \tcode{\{1, 2\}} \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared_for_overwrite(); template constexpr shared_ptr allocate_shared_for_overwrite(const A& a); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is not an array of unknown bound. \pnum \returns A \tcode{shared_ptr} to an object of type \tcode{T}. \pnum \begin{example} \begin{codeblock} struct X { double data[1024]; }; shared_ptr p = make_shared_for_overwrite(); // \tcode{shared_ptr} to a default-initialized \tcode{X}, where each element in \tcode{X::data} has an indeterminate value shared_ptr q = make_shared_for_overwrite(); // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value \end{codeblock} \end{example} \end{itemdescr} \indexlibraryglobal{make_shared}% \indexlibraryglobal{allocate_shared}% \begin{itemdecl} template constexpr shared_ptr make_shared_for_overwrite(size_t N); template constexpr shared_ptr allocate_shared_for_overwrite(const A& a, size_t N); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{T} is an array of unknown bound. \pnum \returns A \tcode{shared_ptr} to an array of \tcode{N} elements of type \tcode{remove_extent_t}. \pnum \begin{example} \begin{codeblock} shared_ptr p = make_shared_for_overwrite(1024); // \tcode{shared_ptr} to a default-initialized \tcode{double[1024]}, where each element has an indeterminate value \end{codeblock} \end{example} \end{itemdescr} \rSec4[util.smartptr.shared.cmp]{Comparison} \indexlibrarymember{operator==}{shared_ptr}% \begin{itemdecl} template constexpr bool operator==(const shared_ptr& a, const shared_ptr& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{a.get() == b.get()}. \end{itemdescr} \indexlibrarymember{operator==}{shared_ptr}% \begin{itemdecl} template constexpr bool operator==(const shared_ptr& a, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{!a}. \end{itemdescr} \indexlibrarymember{operator<=>}{shared_ptr}% \begin{itemdecl} template constexpr strong_ordering operator<=>(const shared_ptr& a, const shared_ptr& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{compare_three_way()(a.get(), b.get())}. \pnum \begin{note} Defining a comparison operator function allows \tcode{shared_ptr} objects to be used as keys in associative containers. \end{note} \end{itemdescr} \indexlibrarymember{operator<=>}{shared_ptr}% \begin{itemdecl} template constexpr strong_ordering operator<=>(const shared_ptr& a, nullptr_t) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \begin{codeblock} compare_three_way()(a.get(), static_cast::element_type*>(nullptr)) \end{codeblock} \end{itemdescr} \rSec4[util.smartptr.shared.spec]{Specialized algorithms} \indexlibrarymember{swap}{shared_ptr}% \begin{itemdecl} template constexpr void swap(shared_ptr& a, shared_ptr& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{a.swap(b)}. \end{itemdescr} \rSec4[util.smartptr.shared.cast]{Casts} \indexlibrarymember{static_pointer_cast}{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr static_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr static_pointer_cast(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{static_cast((U*)nullptr)} is well-formed. \pnum \returns \begin{codeblock} shared_ptr(@\placeholder{R}@, static_cast::element_type*>(r.get())) \end{codeblock} where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and \tcode{std::move(r)} for the second. \pnum \begin{note} The seemingly equivalent expression \tcode{shared_ptr(static_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} \indexlibrarymember{dynamic_pointer_cast}{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr dynamic_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr dynamic_pointer_cast(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{dynamic_cast((U*)nullptr)} is well-formed. The expression \tcode{dynamic_cast::element_type*>(r.get())} is well-formed. \pnum \expects The expression \tcode{dynamic_cast::element_type*>(r.get())} has well-defined behavior. \pnum \returns \begin{itemize} \item When \tcode{dynamic_cast::element_type*>(r.get())} returns a non-null value \tcode{p}, \tcode{shared_ptr(\placeholder{R}, p)}, where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and \tcode{std::move(r)} for the second. \item Otherwise, \tcode{shared_ptr()}. \end{itemize} \pnum \begin{note} The seemingly equivalent expression \tcode{shared_ptr(dynamic_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} \indexlibrarymember{const_pointer_cast}{shared_ptr}% \begin{itemdecl} template constexpr shared_ptr const_pointer_cast(const shared_ptr& r) noexcept; template constexpr shared_ptr const_pointer_cast(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{const_cast((U*)nullptr)} is well-formed. \pnum \returns \begin{codeblock} shared_ptr(@\placeholder{R}@, const_cast::element_type*>(r.get())) \end{codeblock} where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and \tcode{std::move(r)} for the second. \pnum \begin{note} The seemingly equivalent expression \tcode{shared_ptr(const_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} \indexlibrarymember{reinterpret_pointer_cast}{shared_ptr}% \begin{itemdecl} template shared_ptr reinterpret_pointer_cast(const shared_ptr& r) noexcept; template shared_ptr reinterpret_pointer_cast(shared_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{reinterpret_cast((U*)nullptr)} is well-formed. \pnum \returns \begin{codeblock} shared_ptr(@\placeholder{R}@, reinterpret_cast::element_type*>(r.get())) \end{codeblock} where \tcode{\placeholder{R}} is \tcode{r} for the first overload, and \tcode{std::move(r)} for the second. \pnum \begin{note} The seemingly equivalent expression \tcode{shared_ptr(reinterpret_cast(r.get()))} can result in undefined behavior, attempting to delete the same object twice. \end{note} \end{itemdescr} \rSec4[util.smartptr.getdeleter]{\tcode{get_deleter}} \indexlibrarymember{get_deleter}{shared_ptr}% \begin{itemdecl} template constexpr D* get_deleter(const shared_ptr& p) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns If \tcode{p} owns a deleter \tcode{d} of type cv-unqualified \tcode{D}, returns \tcode{addressof(d)}; otherwise returns \keyword{nullptr}. The returned pointer remains valid as long as there exists a \tcode{shared_ptr} instance that owns \tcode{d}. \begin{note} It is unspecified whether the pointer remains valid longer than that. This can happen if the implementation doesn't destroy the deleter until all \tcode{weak_ptr} instances that share ownership with \tcode{p} have been destroyed. \end{note} \end{itemdescr} \rSec4[util.smartptr.shared.io]{I/O} \indexlibrarymember{operator<<}{shared_ptr}% \begin{itemdecl} template basic_ostream& operator<<(basic_ostream& os, const shared_ptr& p); \end{itemdecl} \begin{itemdescr} \pnum \effects As if by: \tcode{os <{}< p.get();} \pnum \returns \tcode{os}. \end{itemdescr} \rSec3[util.smartptr.weak]{Class template \tcode{weak_ptr}} \rSec4[util.smartptr.weak.general]{General} \pnum \indexlibraryglobal{weak_ptr}% The \tcode{weak_ptr} class template stores a weak reference to an object that is already managed by a \tcode{shared_ptr}. To access the object, a \tcode{weak_ptr} can be converted to a \tcode{shared_ptr} using the member function \tcode{lock}. \begin{codeblock} namespace std { template class weak_ptr { public: using element_type = remove_extent_t; // \ref{util.smartptr.weak.const}, constructors constexpr weak_ptr() noexcept; template constexpr weak_ptr(const shared_ptr& r) noexcept; constexpr weak_ptr(const weak_ptr& r) noexcept; template constexpr weak_ptr(const weak_ptr& r) noexcept; constexpr weak_ptr(weak_ptr&& r) noexcept; template constexpr weak_ptr(weak_ptr&& r) noexcept; // \ref{util.smartptr.weak.dest}, destructor constexpr ~weak_ptr(); // \ref{util.smartptr.weak.assign}, assignment constexpr weak_ptr& operator=(const weak_ptr& r) noexcept; template constexpr weak_ptr& operator=(const weak_ptr& r) noexcept; template constexpr weak_ptr& operator=(const shared_ptr& r) noexcept; constexpr weak_ptr& operator=(weak_ptr&& r) noexcept; template constexpr weak_ptr& operator=(weak_ptr&& r) noexcept; // \ref{util.smartptr.weak.mod}, modifiers constexpr void swap(weak_ptr& r) noexcept; constexpr void reset() noexcept; // \ref{util.smartptr.weak.obs}, observers constexpr long use_count() const noexcept; constexpr bool expired() const noexcept; constexpr shared_ptr lock() const noexcept; template bool owner_before(const shared_ptr& b) const noexcept; template bool owner_before(const weak_ptr& b) const noexcept; size_t owner_hash() const noexcept; template constexpr bool owner_equal(const shared_ptr& b) const noexcept; template constexpr bool owner_equal(const weak_ptr& b) const noexcept; }; template weak_ptr(shared_ptr) -> weak_ptr; } \end{codeblock} \pnum Specializations of \tcode{weak_ptr} shall be \oldconceptref{CopyConstructible} and \oldconceptref{CopyAssignable}, allowing their use in standard containers. The template parameter \tcode{T} of \tcode{weak_ptr} may be an incomplete type. \rSec4[util.smartptr.weak.const]{Constructors} \indexlibraryctor{weak_ptr}% \begin{itemdecl} constexpr weak_ptr() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Constructs an empty \tcode{weak_ptr} object that stores a null pointer value. \pnum \ensures \tcode{use_count() == 0}. \end{itemdescr} \indexlibraryctor{weak_ptr}% \begin{itemdecl} constexpr weak_ptr(const weak_ptr& r) noexcept; template constexpr weak_ptr(const weak_ptr& r) noexcept; template constexpr weak_ptr(const shared_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the second and third constructors, \tcode{Y*} is compatible with \tcode{T*}. \pnum \effects If \tcode{r} is empty, constructs an empty \tcode{weak_ptr} object that stores a null pointer value; otherwise, constructs a \tcode{weak_ptr} object that shares ownership with \tcode{r} and stores a copy of the pointer stored in \tcode{r}. \pnum \ensures \tcode{use_count() == r.use_count()}. \end{itemdescr} \indexlibraryctor{weak_ptr}% \begin{itemdecl} constexpr weak_ptr(weak_ptr&& r) noexcept; template constexpr weak_ptr(weak_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints For the second constructor, \tcode{Y*} is compatible with \tcode{T*}. \pnum \effects Move constructs a \tcode{weak_ptr} instance from \tcode{r}. \pnum \ensures \tcode{*this} contains the old value of \tcode{r}. \tcode{r} is empty, stores a null pointer value, and \tcode{r.use_count() == 0}. \end{itemdescr} \rSec4[util.smartptr.weak.dest]{Destructor} \indexlibrarydtor{weak_ptr}% \begin{itemdecl} constexpr ~weak_ptr(); \end{itemdecl} \begin{itemdescr} \pnum \effects Destroys this \tcode{weak_ptr} object but has no effect on the object its stored pointer points to. \end{itemdescr} \rSec4[util.smartptr.weak.assign]{Assignment} \indexlibrarymember{operator=}{weak_ptr}% \begin{itemdecl} constexpr weak_ptr& operator=(const weak_ptr& r) noexcept; template constexpr weak_ptr& operator=(const weak_ptr& r) noexcept; template constexpr weak_ptr& operator=(const shared_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{weak_ptr(r).swap(*this)}. \pnum \returns \tcode{*this}. \pnum \remarks The implementation may meet the effects (and the implied guarantees) via different means, without creating a temporary object. \end{itemdescr} \indexlibrarymember{operator=}{weak_ptr}% \begin{itemdecl} constexpr weak_ptr& operator=(weak_ptr&& r) noexcept; template constexpr weak_ptr& operator=(weak_ptr&& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{weak_ptr(std::move(r)).swap(*this)}. \pnum \returns \tcode{*this}. \end{itemdescr} \rSec4[util.smartptr.weak.mod]{Modifiers} \indexlibrarymember{swap}{weak_ptr}% \begin{itemdecl} constexpr void swap(weak_ptr& r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Exchanges the contents of \tcode{*this} and \tcode{r}. \end{itemdescr} \indexlibrarymember{reset}{weak_ptr}% \begin{itemdecl} constexpr void reset() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{weak_ptr().swap(*this)}. \end{itemdescr} \rSec4[util.smartptr.weak.obs]{Observers} \indexlibrarymember{use_count}{weak_ptr}% \begin{itemdecl} constexpr long use_count() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{0} if \tcode{*this} is empty; otherwise, the number of \tcode{shared_ptr} instances that share ownership with \tcode{*this}. \end{itemdescr} \indexlibrarymember{expired}{weak_ptr}% \begin{itemdecl} constexpr bool expired() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{use_count() == 0}. \end{itemdescr} \indexlibrarymember{lock}{weak_ptr}% \begin{itemdecl} constexpr shared_ptr lock() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{expired() ?\ shared_ptr() :\ shared_ptr(*this)}, executed atomically. \end{itemdescr} \indexlibrarymember{owner_before}{weak_ptr}% \begin{itemdecl} template bool owner_before(const shared_ptr& b) const noexcept; template bool owner_before(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An unspecified value such that \begin{itemize} \item \tcode{owner_before(b)} defines a strict weak ordering as defined in~\ref{alg.sorting}; \item \tcode{!owner_before(b) \&\& !b.owner_before(*this)} is \tcode{true} if and only if \tcode{owner_equal(b)} is \tcode{true}. \end{itemize} \end{itemdescr} \indexlibrarymember{owner_hash}{weak_ptr}% \begin{itemdecl} size_t owner_hash() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns An unspecified value such that, for any object \tcode{x} where \tcode{owner_equal(x)} is \tcode{true}, \tcode{owner_hash() == x.owner_hash()} is \tcode{true}. \end{itemdescr} \indexlibrarymember{owner_equal}{weak_ptr}% \begin{itemdecl} template constexpr bool owner_equal(const shared_ptr& b) const noexcept; template constexpr bool owner_equal(const weak_ptr& b) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if and only if \tcode{*this} and \tcode{b} share ownership or are both empty. Otherwise returns \tcode{false}. \pnum \remarks \tcode{owner_equal} is an equivalence relation. \end{itemdescr} \rSec4[util.smartptr.weak.spec]{Specialized algorithms} \indexlibrarymember{swap}{weak_ptr}% \begin{itemdecl} template constexpr void swap(weak_ptr& a, weak_ptr& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{a.swap(b)}. \end{itemdescr} \rSec3[util.smartptr.ownerless]{Class template \tcode{owner_less}} \pnum The class template \tcode{owner_less} allows ownership-based mixed comparisons of shared and weak pointers. \indexlibraryglobal{owner_less}% \begin{codeblock} namespace std { template struct owner_less; template struct owner_less> { bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template struct owner_less> { bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; }; template<> struct owner_less { template bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; template bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; template bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; template bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; using is_transparent = @\unspec@; }; } \end{codeblock} \indexlibrarymember{operator()}{owner_less}% \pnum \tcode{operator()(x, y)} returns \tcode{x.owner_before(y)}. \begin{note} Note that \begin{itemize} \item \tcode{operator()} defines a strict weak ordering as defined in~\ref{alg.sorting}; \item \tcode{!operator()(a, b) \&\& !operator()(b, a)} is \tcode{true} if and only if \tcode{a.owner_equal(b)} is \tcode{true}. \end{itemize} \end{note} \rSec3[util.smartptr.owner.hash]{Struct \tcode{owner_hash}} \pnum The class \tcode{owner_hash} provides ownership-based hashing. \indexlibraryglobal{owner_hash}% \begin{codeblock} namespace std { struct owner_hash { template size_t operator()(const shared_ptr&) const noexcept; template size_t operator()(const weak_ptr&) const noexcept; using is_transparent = @\unspec@; }; } \end{codeblock} \indexlibrarymember{operator()}{owner_hash}% \begin{itemdecl} template size_t operator()(const shared_ptr& x) const noexcept; template size_t operator()(const weak_ptr& x) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{x.owner_hash()}. \pnum \begin{note} For any object \tcode{y} where \tcode{x.owner_equal(y)} is \tcode{true}, \tcode{x.owner_hash() == y.owner_hash()} is \tcode{true}. \end{note} \end{itemdescr} \rSec3[util.smartptr.owner.equal]{Struct \tcode{owner_equal}} \pnum The class \tcode{owner_equal} provides ownership-based mixed equality comparisons of shared and weak pointers. \indexlibraryglobal{owner_equal}% \begin{codeblock} namespace std { struct owner_equal { template constexpr bool operator()(const shared_ptr&, const shared_ptr&) const noexcept; template constexpr bool operator()(const shared_ptr&, const weak_ptr&) const noexcept; template constexpr bool operator()(const weak_ptr&, const shared_ptr&) const noexcept; template constexpr bool operator()(const weak_ptr&, const weak_ptr&) const noexcept; using is_transparent = @\unspec@; }; } \end{codeblock} \indexlibrarymember{operator()}{owner_equal}% \begin{itemdecl} template constexpr bool operator()(const shared_ptr& x, const shared_ptr& y) const noexcept; template constexpr bool operator()(const shared_ptr& x, const weak_ptr& y) const noexcept; template constexpr bool operator()(const weak_ptr& x, const shared_ptr& y) const noexcept; template constexpr bool operator()(const weak_ptr& x, const weak_ptr& y) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{x.owner_equal(y)}. \pnum \begin{note} \tcode{x.owner_equal(y)} is \tcode{true} if and only if \tcode{x} and \tcode{y} share ownership or are both empty. \end{note} \end{itemdescr} \rSec3[util.smartptr.enab]{Class template \tcode{enable_shared_from_this}} \pnum \indexlibraryglobal{enable_shared_from_this}% A class \tcode{T} can inherit from \tcode{enable_shared_from_this} to inherit the \tcode{shared_from_this} member functions that obtain a \tcode{shared_ptr} instance pointing to \tcode{*this}. \pnum \begin{example} \begin{codeblock} struct X: public enable_shared_from_this { }; int main() { shared_ptr p(new X); shared_ptr q = p->shared_from_this(); assert(p == q); assert(p.owner_equal(q)); // \tcode{p} and \tcode{q} share ownership } \end{codeblock} \end{example} \begin{codeblock} namespace std { template class enable_shared_from_this { protected: constexpr enable_shared_from_this() noexcept; constexpr enable_shared_from_this(const enable_shared_from_this&) noexcept; constexpr enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; constexpr ~enable_shared_from_this(); public: constexpr shared_ptr shared_from_this(); constexpr shared_ptr shared_from_this() const; constexpr weak_ptr weak_from_this() noexcept; constexpr weak_ptr weak_from_this() const noexcept; private: mutable weak_ptr @\exposid{weak-this}@; // \expos }; } \end{codeblock} \pnum The template parameter \tcode{T} of \tcode{enable_shared_from_this} may be an incomplete type. \indexlibraryctor{enable_shared_from_this}% \begin{itemdecl} constexpr enable_shared_from_this() noexcept; constexpr enable_shared_from_this(const enable_shared_from_this&) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Value-initializes \exposid{weak-this}. \end{itemdescr} \indexlibrarymember{operator=}{enable_shared_from_this}% \begin{itemdecl} constexpr enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{*this}. \pnum \begin{note} \exposid{weak-this} is not changed. \end{note} \end{itemdescr} \indexlibraryglobal{shared_ptr}% \indexlibrarymember{shared_from_this}{enable_shared_from_this}% \begin{itemdecl} constexpr shared_ptr shared_from_this(); constexpr shared_ptr shared_from_this() const; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{shared_ptr(\exposid{weak-this})}. \end{itemdescr} \indexlibraryglobal{weak_ptr}% \indexlibrarymember{weak_from_this}{enable_shared_from_this}% \begin{itemdecl} constexpr weak_ptr weak_from_this() noexcept; constexpr weak_ptr weak_from_this() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \exposid{weak-this}. \end{itemdescr} \rSec2[util.smartptr.hash]{Smart pointer hash support} \indexlibrarymember{hash}{unique_ptr}% \begin{itemdecl} template struct hash>; \end{itemdecl} \begin{itemdescr} \pnum Letting \tcode{UP} be \tcode{unique_ptr}, the specialization \tcode{hash} is enabled\iref{unord.hash} if and only if \tcode{hash} is enabled. When enabled, for an object \tcode{p} of type \tcode{UP}, \tcode{hash()(p)} evaluates to the same value as \tcode{hash()(p.get())}. The member functions are not guaranteed to be \keyword{noexcept}. \end{itemdescr} \indexlibrarymember{hash}{shared_ptr}% \begin{itemdecl} template struct hash>; \end{itemdecl} \begin{itemdescr} \pnum For an object \tcode{p} of type \tcode{shared_ptr}, \tcode{hash>()(p)} evaluates to the same value as \tcode{hash::element_type*>()(p.get())}. \end{itemdescr}% \indextext{smart pointers|)} \rSec2[smartptr.adapt]{Smart pointer adaptors} \rSec3[out.ptr.t]{Class template \tcode{out_ptr_t}} \pnum \tcode{out_ptr_t} is a class template used to adapt types such as smart pointers\iref{smartptr} for functions that use output pointer parameters. \pnum \begin{example} \begin{codeblock} #include #include int fopen_s(std::FILE** f, const char* name, const char* mode); struct fclose_deleter { void operator()(std::FILE* f) const noexcept { std::fclose(f); } }; int main(int, char*[]) { constexpr const char* file_name = "ow.o"; std::unique_ptr file_ptr; int err = fopen_s(std::out_ptr(file_ptr), file_name, "r+b"); if (err != 0) return 1; // \tcode{*file_ptr} is valid return 0; } \end{codeblock} \tcode{unique_ptr} can be used with \tcode{out_ptr} to be passed into an output pointer-style function, without needing to hold onto an intermediate pointer value and manually delete it on error or failure. \end{example} \indexlibraryglobal{out_ptr_t}% \begin{codeblock} namespace std { template class out_ptr_t { public: constexpr explicit out_ptr_t(Smart&, Args...); out_ptr_t(const out_ptr_t&) = delete; constexpr ~out_ptr_t(); constexpr operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // \expos tuple a; // \expos Pointer p; // \expos }; } \end{codeblock} \pnum \tcode{Pointer} shall meet the \oldconceptref{NullablePointer} requirements. If \tcode{Smart} is a specialization of \tcode{shared_ptr} and \tcode{sizeof...(Args) == 0}, the program is ill-formed. \begin{note} It is typically a user error to reset a \tcode{shared_ptr} without specifying a deleter, as \tcode{shared_ptr} will replace a custom deleter upon usage of \tcode{reset}, as specified in \ref{util.smartptr.shared.mod}. \end{note} \pnum Program-defined specializations of \tcode{out_ptr_t} that depend on at least one program-defined type need not meet the requirements for the primary template. \pnum Evaluations of the conversion functions on the same object may conflict\iref{intro.races}. \indexlibraryctor{out_ptr_t}% \begin{itemdecl} constexpr explicit out_ptr_t(Smart& smart, Args... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{s} with \tcode{smart}, \tcode{a} with \tcode{std::forward(args)...}, and value-initializes \tcode{p}. Then, equivalent to: \begin{itemize} \item % pretend to \item that there is real text here, but undo the vertical spacing \mbox{}\vspace{-\baselineskip}\vspace{-\parskip} \begin{codeblock} s.reset(); \end{codeblock} if the expression \tcode{s.reset()} is well-formed; \item otherwise, \begin{codeblock} s = Smart(); \end{codeblock} if \tcode{is_constructible_v} is \tcode{true}; \item otherwise, the program is ill-formed. \end{itemize} \pnum \begin{note} The constructor is not \tcode{noexcept} to allow for a variety of non-terminating and safe implementation strategies. For example, an implementation can allocate a \tcode{shared_ptr}'s internal node in the constructor and let implementation-defined exceptions escape safely. The destructor can then move the allocated control block in directly and avoid any other exceptions. \end{note} \end{itemdescr} \indexlibrarydtor{out_ptr_t}% \begin{itemdecl} constexpr ~out_ptr_t(); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{SP} be \tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. \pnum \effects Equivalent to: \begin{itemize} \item % pretend to \item that there is real text here, but undo the vertical spacing \mbox{}\vspace{-\baselineskip}\vspace{-\parskip} \begin{codeblock} if (p) { apply([&](auto&&... args) { s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); } \end{codeblock} if the expression \tcode{s.reset(static_cast(p), std::forward(args)...)} is well-formed; \item otherwise, \begin{codeblock} if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); } \end{codeblock} if \tcode{is_constructible_v} is \tcode{true}; \item otherwise, the program is ill-formed. \end{itemize} \end{itemdescr} \begin{itemdecl} constexpr operator Pointer*() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{operator void**()} has not been called on \tcode{*this}. \pnum \returns \tcode{addressof(const_cast(p))}. \end{itemdescr} \begin{itemdecl} operator void**() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_same_v} is \tcode{false}. \pnum \mandates \tcode{is_pointer_v} is \tcode{true}. \pnum \expects \tcode{operator Pointer*()} has not been called on \tcode{*this}. \pnum \returns A pointer value \tcode{v} such that: \begin{itemize} \item the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and \item any modification of \tcode{*v} that is not followed by a subsequent modification of \tcode{*this} affects the value of \tcode{p} during the destruction of \tcode{*this}, such that \tcode{static_cast(p) == *v}. \end{itemize} \pnum \remarks Accessing \tcode{*v} outside the lifetime of \tcode{*this} has undefined behavior. \pnum \begin{note} \tcode{reinterpret_cast(static_cast(*this))} can be a viable implementation strategy for some implementations. \end{note} \end{itemdescr} \rSec3[out.ptr]{Function template \tcode{out_ptr}} \indexlibraryglobal{out_ptr}% \begin{itemdecl} template constexpr auto out_ptr(Smart& s, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{P} be \tcode{Pointer} if \tcode{is_void_v} is \tcode{false}, otherwise \tcode{\exposid{POINTER_OF}(Smart)}. \pnum \returns \tcode{out_ptr_t(s, std::forward(args)...)}. \end{itemdescr} \rSec3[inout.ptr.t]{Class template \tcode{inout_ptr_t}} \pnum \tcode{inout_ptr_t} is a class template used to adapt types such as smart pointers\iref{smartptr} for functions that use output pointer parameters whose dereferenced values may first be deleted before being set to another allocated value. \pnum \begin{example} \begin{codeblock} #include struct star_fish* star_fish_alloc(); int star_fish_populate(struct star_fish** ps, const char* description); struct star_fish_deleter { void operator() (struct star_fish* c) const noexcept; }; using star_fish_ptr = std::unique_ptr; int main(int, char*[]) { star_fish_ptr peach(star_fish_alloc()); // ... // used, need to re-make int err = star_fish_populate(std::inout_ptr(peach), "caring clown-fish liker"); return err; } \end{codeblock} A \tcode{unique_ptr} can be used with \tcode{inout_ptr} to be passed into an output pointer-style function. The original value will be properly deleted according to the function it is used with and a new value reset in its place. \end{example} \indexlibraryglobal{inout_ptr_t}% \begin{codeblock} namespace std { template class inout_ptr_t { public: constexpr explicit inout_ptr_t(Smart&, Args...); inout_ptr_t(const inout_ptr_t&) = delete; constexpr ~inout_ptr_t(); constexpr operator Pointer*() const noexcept; operator void**() const noexcept; private: Smart& s; // \expos tuple a; // \expos Pointer p; // \expos }; } \end{codeblock} \pnum \tcode{Pointer} shall meet the \oldconceptref{NullablePointer} requirements. If \tcode{Smart} is a specialization of \tcode{shared_ptr}, the program is ill-formed. \begin{note} It is impossible to properly acquire unique ownership of the managed resource from a \tcode{shared_ptr} given its shared ownership model. \end{note} \pnum Program-defined specializations of \tcode{inout_ptr_t} that depend on at least one program-defined type need not meet the requirements for the primary template. \pnum Evaluations of the conversion functions on the same object may conflict\iref{intro.races}. \indexlibraryctor{inout_ptr_t}% \begin{itemdecl} constexpr explicit inout_ptr_t(Smart& smart, Args... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes \tcode{s} with \tcode{smart}, \tcode{a} with \tcode{std::forward(args)...}, and \tcode{p} to either \begin{itemize} \item \tcode{smart} if \tcode{is_pointer_v} is \tcode{true}, \item otherwise, \tcode{smart.get()}. \end{itemize} \pnum \remarks An implementation can call \tcode{s.release()}. \pnum \begin{note} The constructor is not \tcode{noexcept} to allow for a variety of non-terminating and safe implementation strategies. For example, an intrusive pointer implementation with a control block can allocate in the constructor and safely fail with an exception. \end{note} \end{itemdescr} \indexlibrarydtor{inout_ptr_t}% \begin{itemdecl} constexpr ~inout_ptr_t(); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{SP} be \tcode{\exposid{POINTER_OF_OR}(Smart, Pointer)}\iref{memory.general}. \pnum Let \exposid{release-statement} be \tcode{s.release();} if an implementation does not call \tcode{s.release()} in the constructor. Otherwise, it is empty. \pnum \effects Equivalent to: \begin{itemize} \item % pretend to \item that there is real text here, but undo the vertical spacing \mbox{}\vspace{-\baselineskip}\vspace{-\parskip} \begin{codeblock} apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); \end{codeblock} if \tcode{is_pointer_v} is \tcode{true}; \item otherwise, \begin{codeblock} @\exposid{release-statement}@; if (p) { apply([&](auto&&... args) { s.reset(static_cast(p), std::forward(args)...); }, std::move(a)); } \end{codeblock} if the expression \tcode{s.reset(static_cast(p), std::forward(args)...)} is well-\newline formed; \item otherwise, \begin{codeblock} @\exposid{release-statement}@; if (p) { apply([&](auto&&... args) { s = Smart(static_cast(p), std::forward(args)...); }, std::move(a)); } \end{codeblock} if \tcode{is_constructible_v} is \tcode{true}; \item otherwise, the program is ill-formed. \end{itemize} \end{itemdescr} \begin{itemdecl} constexpr operator Pointer*() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{operator void**()} has not been called on \tcode{*this}. \pnum \returns \tcode{addressof(const_cast(p))}. \end{itemdescr} \begin{itemdecl} operator void**() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_same_v} is \tcode{false}. \pnum \mandates \tcode{is_pointer_v} is \tcode{true}. \pnum \expects \tcode{operator Pointer*()} has not been called on \tcode{*this}. \pnum \returns A pointer value \tcode{v} such that: \begin{itemize} \item the initial value \tcode{*v} is equivalent to \tcode{static_cast(p)} and \item any modification of \tcode{*v} that is not followed by subsequent modification of \tcode{*this} affects the value of \tcode{p} during the destruction of \tcode{*this}, such that \tcode{static_cast(p) == *v}. \end{itemize} \pnum \remarks Accessing \tcode{*v} outside the lifetime of \tcode{*this} has undefined behavior. \pnum \begin{note} \tcode{reinterpret_cast(static_cast(*this))} can be a viable implementation strategy for some implementations. \end{note} \end{itemdescr} \rSec3[inout.ptr]{Function template \tcode{inout_ptr}} \indexlibraryglobal{inout_ptr}% \begin{itemdecl} template constexpr auto inout_ptr(Smart& s, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum Let \tcode{P} be \tcode{Pointer} if \tcode{is_void_v} is \tcode{false}, otherwise \tcode{\exposid{POINTER_OF}(Smart)}. \pnum \returns \tcode{inout_ptr_t(s, std::forward(args)...)}. \end{itemdescr} \rSec1[mem.composite.types]{Types for composite class design} \rSec2[indirect]{Class template \tcode{indirect}} \rSec3[indirect.general]{General} \pnum An indirect object manages the lifetime of an owned object. An indirect object is \defnx{valueless}{valueless!indirect object} if it has no owned object. An indirect object may become valueless only after it has been moved from. \pnum In every specialization \tcode{indirect}, if the type \tcode{allocator_traits::value_type} is not the same type as \tcode{T}, the program is ill-formed. Every object of type \tcode{indirect} uses an object of type \tcode{Allocator} to allocate and free storage for the owned object as needed. \pnum Constructing an owned object with \tcode{args...} using the allocator \tcode{a} means calling \tcode{allocator_traits::construct(a, \exposid{p}, args...)} where \tcode{args} is an expression pack, \tcode{a} is an allocator, and \exposid{p} is a pointer obtained by calling \tcode{allocator_traits::allocate}. \pnum The member \exposid{alloc} is used for any memory allocation and element construction performed by member functions during the lifetime of each indirect object. The allocator \exposid{alloc} may be replaced only via assignment or \tcode{swap()}. \tcode{Allocator} replacement is performed by copy assignment, move assignment, or swapping of the allocator only if\iref{container.reqmts}: \begin{itemize} \item \tcode{allocator_traits::propagate_on_container_copy_assignment::value}, or \item \tcode{allocator_traits::propagate_on_container_move_assignment::value}, or \item \tcode{allocator_traits::propagate_on_container_swap::value} \end{itemize} is \tcode{true} within the implementation of the corresponding \tcode{indirect} operation. \pnum A program that instantiates the definition of the template \tcode{indirect} with a type for the \tcode{T} parameter that is a non-object type, an array type, \tcode{in_place_t}, a specialization of \tcode{in_place_type_t}, or a cv-qualified type is ill-formed. \pnum The template parameter \tcode{T} of \tcode{indirect} may be an incomplete type. \pnum The template parameter \tcode{Allocator} of \tcode{indirect} shall meet the \oldconcept{Allocator} requirements. \pnum If a program declares an explicit or partial specialization of \tcode{indirect}, the behavior is undefined. \rSec3[indirect.syn]{Synopsis} \indexlibraryglobal{indirect}% \begin{codeblock} namespace std { template> class indirect { public: using value_type = T; using allocator_type = Allocator; using pointer = allocator_traits::pointer; using const_pointer = allocator_traits::const_pointer; // \ref{indirect.ctor}, constructors constexpr explicit indirect(); constexpr explicit indirect(allocator_arg_t, const Allocator& a); constexpr indirect(const indirect& other); constexpr indirect(allocator_arg_t, const Allocator& a, const indirect& other); constexpr indirect(indirect&& other) noexcept; constexpr indirect(allocator_arg_t, const Allocator& a, indirect&& other) noexcept(@\seebelow@); template constexpr explicit indirect(U&& u); template constexpr explicit indirect(allocator_arg_t, const Allocator& a, U&& u); template constexpr explicit indirect(in_place_t, Us&&... us); template constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, Us&&... us); template constexpr explicit indirect(in_place_t, initializer_list ilist, Us&&... us); template constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, initializer_list ilist, Us&&... us); // \ref{indirect.dtor}, destructor constexpr ~indirect(); // \ref{indirect.assign}, assignment constexpr indirect& operator=(const indirect& other); constexpr indirect& operator=(indirect&& other) noexcept(@\seebelow@); template constexpr indirect& operator=(U&& u); // \ref{indirect.obs}, observers constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept; constexpr const T&& operator*() const && noexcept; constexpr T&& operator*() && noexcept; constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept; constexpr bool valueless_after_move() const noexcept; constexpr allocator_type get_allocator() const noexcept; // \ref{indirect.swap}, swap constexpr void swap(indirect& other) noexcept(@\seebelow@); friend constexpr void swap(indirect& lhs, indirect& rhs) noexcept(@\seebelow@); // \ref{indirect.relops}, relational operators template friend constexpr bool operator==(const indirect& lhs, const indirect& rhs) noexcept(@\seebelow@); template friend constexpr auto operator<=>(const indirect& lhs, const indirect& rhs) -> @\exposid{synth-three-way-result}@; // \ref{indirect.comp.with.t}, comparison with \tcode{T} template friend constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(@\seebelow@); template friend constexpr auto operator<=>(const indirect& lhs, const U& rhs) -> @\exposid{synth-three-way-result}@; private: pointer @\exposid{p}@; // \expos Allocator @\exposid{alloc}@ = Allocator(); // \expos }; template indirect(Value) -> indirect; template indirect(allocator_arg_t, Allocator, Value) -> indirect::template rebind_alloc>; } \end{codeblock} \rSec3[indirect.ctor]{Constructors} \pnum The following element applies to all functions in~\ref{indirect.ctor}: \begin{itemdescr} \pnum \throws Nothing unless \tcode{allocator_traits::allocate} or \tcode{allocator_traits::construct} throws. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr explicit indirect(); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_default_constructible_v} is \tcode{true}. \pnum \mandates \tcode{is_default_constructible_v} is \tcode{true}. \pnum \effects Constructs an owned object of type \tcode{T} with an empty argument list, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr explicit indirect(allocator_arg_t, const Allocator& a); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_default_constructible_v} is \tcode{true}. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{T} with an empty argument list, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr indirect(const indirect& other); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_copy_constructible_v} is \tcode{true}. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{allocator_traits::select_on_contai\-ner_copy_construction(other.\exposid{alloc})}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, constructs an owned object of type \tcode{T} with \tcode{*other}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr indirect(allocator_arg_t, const Allocator& a, const indirect& other); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{is_copy_constructible_v} is \tcode{true}. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, constructs an owned object of type \tcode{T} with \tcode{*other}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr indirect(indirect&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects \exposid{alloc} is direct-non-list-initialized from \tcode{std::move(other.\exposid{alloc})}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise \tcode{*this} takes ownership of the owned object of \tcode{other}. \pnum \ensures \tcode{other} is valueless. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} constexpr indirect(allocator_arg_t, const Allocator& a, indirect&& other) noexcept(allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \mandates If \tcode{allocator_traits::is_always_equal::value} is \tcode{false} then \tcode{T} is a complete type. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, constructs an object of type \tcode{indirect} that takes ownership of the owned object of \tcode{other}. Otherwise, constructs an owned object of type \tcode{T} with \tcode{*std::move(other)}, using the allocator \exposid{alloc}. \pnum \ensures \tcode{other} is valueless. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(U&& u); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, indirect>} is \tcode{false}, \item \tcode{is_same_v, in_place_t>} is \tcode{false}, \item \tcode{is_constructible_v} is \tcode{true}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{T} with \tcode{std::forward(u)}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(allocator_arg_t, const Allocator& a, U&& u); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, indirect>} is \tcode{false}, \item \tcode{is_same_v, in_place_t>} is \tcode{false}, and \item \tcode{is_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{T} with \tcode{std::forward(u)}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(in_place_t, Us&&... us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_constructible_v} is \tcode{true}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{T} with \tcode{std::forward(us)...}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, Us&& ...us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v} is \tcode{true}. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{T} with \tcode{std::forward(us)...}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(in_place_t, initializer_list ilist, Us&&... us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_constructible_v\&, Us...>} is \tcode{true}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{T} with the arguments \tcode{ilist, std::forward(us)...}, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{indirect}% \begin{itemdecl} template constexpr explicit indirect(allocator_arg_t, const Allocator& a, in_place_t, initializer_list ilist, Us&&... us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v\&, Us...>} is \tcode{true}. \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{T} with the arguments \tcode{ilist, std::forward(us)...}, using the allocator \exposid{alloc}. \end{itemdescr} \rSec3[indirect.dtor]{Destructor} \indexlibrarydtor{indirect}% \begin{itemdecl} constexpr ~indirect(); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type. \pnum \effects If \tcode{*this} is not valueless, destroys the owned object using \tcode{allocator_traits::de\-stroy} and then the storage is deallocated. \end{itemdescr} \rSec3[indirect.assign]{Assignment} \indexlibrarymember{operator=}{indirect}% \begin{itemdecl} constexpr indirect& operator=(const indirect& other); \end{itemdecl} \begin{itemdescr} \pnum \mandates \begin{itemize} \item \tcode{is_copy_assignable_v} is \tcode{true}, and \item \tcode{is_copy_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item %FIXME: We're defining what it means for an allocator to "need updating" here? %FIXME: (Note: that this concept is used elsewhere so it must be defined)... %FIXME: How is this an "effect"? The allocator needs updating if \tcode{allocator_traits::propagate_on_container_copy_assignment::value} is \tcode{true}. \item If \tcode{other} is valueless, \tcode{*this} becomes valueless and the owned object in \tcode{*this}, if any, is destroyed using \tcode{allocator_traits::destroy} and then the storage is deallocated. \item Otherwise, if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true} and \tcode{*this} is not valueless, equivalent to \tcode{**this = *other}. \item Otherwise a new owned object is constructed in \tcode{*this} using \tcode{allocator_traits::con\linebreak{}struct} with the owned object from \tcode{other} as the argument, using either the allocator in \tcode{*this} or %FIXME: Concept "allocator needs updating" not defined/referenced. %FIXME: Same for all usages below. the allocator in \tcode{other} if the allocator needs updating. \item The previously owned object in \tcode{*this}, if any, is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and then the storage is deallocated. \item If the allocator needs updating, the allocator in \tcode{*this} is replaced with a copy of the allocator in \tcode{other}. \end{itemize} \pnum \returns A reference to \tcode{*this}. \pnum \remarks If any exception is thrown, the result of the expression \tcode{this->valueless_after_move()} remains unchanged. If an exception is thrown during the call to \tcode{T}{'s} selected copy constructor, no effect. If an exception is thrown during the call to \tcode{T}{'s} copy assignment, the state of its owned object is as defined by the exception safety guarantee of \tcode{T}{'s} copy assignment. \end{itemdescr} \indexlibrarymember{operator=}{indirect}% \begin{itemdecl} constexpr indirect& operator=(indirect&& other) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \mandates If \tcode{allocator_traits::propagate_on_container_move_assignment::val\-ue} is \tcode{false} and \tcode{allocator_traits::is_always_equal::value} is \tcode{false}, \tcode{is_move_con\-structible_v} is \tcode{true}. \pnum \effects If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item %FIXME: We're defining "allocator needs updating" as an effect? %FIXME: (Same issue as above) The allocator needs updating if \tcode{allocator_traits::propagate_on_container_move_assignment::value} is \tcode{true}. \item If \tcode{other} is valueless, \tcode{*this} becomes valueless. \item Otherwise, if the allocator needs updating or if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, \tcode{*this} takes ownership of the owned object of \tcode{other}. \item Otherwise, constructs a new owned object with %FIXME: "as the argument as an rvalue" is awkward. the owned object of \tcode{other} as the argument as an rvalue, using the allocator in \tcode{*this}. \item The previously owned object in \tcode{*this}, if any, is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and then the storage is deallocated. \item If the allocator needs updating, the allocator in \tcode{*this} is replaced with a copy of the allocator in \tcode{other}. \end{itemize} \pnum \ensures \tcode{other} is valueless. \pnum \returns A reference to \tcode{*this}. \pnum \remarks If any exception is thrown, there are no effects on \tcode{*this} or \tcode{other}. \end{itemdescr} \indexlibrarymember{operator=}{indirect}% \begin{itemdecl} template constexpr indirect& operator=(U&& u); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, indirect>} is \tcode{false}, \item \tcode{is_constructible_v} is \tcode{true}, and \item \tcode{is_assignable_v} is \tcode{true}. \end{itemize} \pnum \effects If \tcode{*this} is valueless then constructs an owned object of type \tcode{T} with \tcode{std::forward(u)} using the allocator \exposid{alloc}. Otherwise, equivalent to \tcode{**this = std::forward(u)}. \pnum \returns A reference to \tcode{*this}. \end{itemdescr} \rSec3[indirect.obs]{Observers} \indexlibrarymember{operator*}{indirect}% \begin{itemdecl} constexpr const T& operator*() const & noexcept; constexpr T& operator*() & noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not valueless. \pnum \returns \tcode{*\exposid{p}}. \end{itemdescr} \indexlibrarymember{operator*}{indirect}% \begin{itemdecl} constexpr const T&& operator*() const && noexcept; constexpr T&& operator*() && noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not valueless. \pnum \returns \tcode{std::move(*\exposid{p})}. \end{itemdescr} \indexlibrarymember{operator->}{indirect}% \begin{itemdecl} constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not valueless. \pnum \returns \exposid{p}. \end{itemdescr} \indexlibrarymember{valueless_after_move}{indirect}% \begin{itemdecl} constexpr bool valueless_after_move() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{*this} is valueless, otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{get_allocator}{indirect}% \begin{itemdecl} constexpr allocator_type get_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \exposid{alloc}. \end{itemdescr} \rSec3[indirect.swap]{Swap} \indexlibrarymember{swap}{indirect}% \begin{itemdecl} constexpr void swap(indirect& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \expects If \tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true}, then \tcode{Allocator} meets the \oldconcept{Swappable} requirements. Otherwise \tcode{get_allocator() == other.\linebreak{}get_allocator()} is \tcode{true}. \pnum \effects Swaps the states of \tcode{*this} and \tcode{other}, exchanging owned objects or valueless states. If \tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true}, then the allocators of \tcode{*this} and \tcode{other} are exchanged by calling \tcode{swap} as described in~\ref{swappable.requirements}. Otherwise, the allocators are not swapped. \begin{note} Does not call \tcode{swap} on the owned objects directly. \end{note} \end{itemdescr} \indexlibrarymember{swap}{indirect}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} constexpr void swap(indirect& lhs, indirect& rhs) noexcept(noexcept(lhs.swap(rhs))); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{lhs.swap(rhs)}. \end{itemdescr} \rSec3[indirect.relops]{Relational operators} \indexlibrarymember{operator==}{indirect}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template constexpr bool operator==(const indirect& lhs, const indirect& rhs) noexcept(noexcept(bool(*lhs == *rhs))); \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{*lhs == *rhs} is well-formed and its result is convertible to \tcode{bool}. \pnum \returns If \tcode{lhs} is valueless or \tcode{rhs} is valueless, \tcode{lhs.valueless_after_move() == rhs.valueless_after_move()}; otherwise \tcode{*lhs == *rhs}. \end{itemdescr} \indexlibrarymember{\exposid{synth-three-way-result}}{indirect}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template constexpr @\exposid{synth-three-way-result}@ operator<=>(const indirect& lhs, const indirect& rhs); \end{itemdecl} \begin{itemdescr} \pnum \returns If \tcode{lhs} is valueless or \tcode{rhs} is valueless, \tcode{!lhs.valueless_after_move() <=> !rhs.value\-less_after_move()}; otherwise \tcode{\exposid{synth-three-way}(*lhs, *rhs)}. \end{itemdescr} \rSec3[indirect.comp.with.t]{Comparison with \tcode{T}} \indexlibrarymember{operator==}{indirect}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template constexpr bool operator==(const indirect& lhs, const U& rhs) noexcept(noexcept(bool(*lhs == rhs))); \end{itemdecl} \begin{itemdescr} \pnum \mandates The expression \tcode{*lhs == rhs} is well-formed and its result is convertible to \tcode{bool}. \pnum \returns If \tcode{lhs} is valueless, \tcode{false}; otherwise \tcode{*lhs == rhs}. \end{itemdescr} \indexlibrarymember{\exposid{synth-three-way-result}}{indirect}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} template constexpr @\exposid{synth-three-way-result}@ operator<=>(const indirect& lhs, const U& rhs); \end{itemdecl} \begin{itemdescr} \pnum \returns If \tcode{lhs} is valueless, \tcode{strong_ordering::less}; otherwise \tcode{\exposid{synth-three-way}(*lhs, rhs)}. \end{itemdescr} \rSec3[indirect.hash]{Hash support} \indexlibrarymember{hash}{indirect}% \begin{itemdecl} template struct hash>; \end{itemdecl} \begin{itemdescr} \pnum The specialization \tcode{hash>} is enabled\iref{unord.hash} if and only if \tcode{hash} is enabled. When enabled for an object \tcode{i} of type \tcode{indirect}, %FIXME: Cleanup wording/punctuation and make consistent. \tcode{hash>()(i)} evaluates to either the same value as \tcode{hash()(*i)}, if \tcode{i} is not valueless; otherwise to an \impldef{result of evaluating \tcode{hash>()(i)} if \tcode{i} is valueless} value. The member functions are not guaranteed to be \tcode{noexcept}. \end{itemdescr} \rSec2[polymorphic]{Class template \tcode{polymorphic}} \rSec3[polymorphic.general]{General} \pnum A polymorphic object manages the lifetime of an owned object. A polymorphic object may own objects of different types at different points in its lifetime. A polymorphic object is \defnx{valueless}{valueless!polymorphic object} if it has no owned object. A polymorphic object may become valueless only after it has been moved from. \pnum In every specialization \tcode{polymorphic}, if the type \tcode{allocator_traits::value_type} is not the same type as \tcode{T}, the program is ill-formed. Every object of type \tcode{polymorphic} uses an object of type \tcode{Allocator} to allocate and free storage for the owned object as needed. \pnum Constructing an owned object of type \tcode{U} with \tcode{args...} using the allocator \tcode{a} means calling \tcode{allocator_traits::construct(a, \exposid{p}, args...)} where \tcode{args} is an expression pack, \tcode{a} is an allocator, and \exposid{p} points to storage suitable for an owned object of type \tcode{U}. \pnum The member \exposid{alloc} is used for any memory allocation and element construction performed by member functions during the lifetime of each polymorphic value object, or until the allocator is replaced. The allocator may be replaced only via assignment or \tcode{swap()}. \tcode{Allocator} replacement is performed by copy assignment, move assignment, or swapping of the allocator only if\iref{container.reqmts}: \begin{itemize} \item \tcode{allocator_traits::propagate_on_container_copy_assignment::value}, or \item \tcode{allocator_traits::propagate_on_container_move_assignment::value}, or \item \tcode{allocator_traits::propagate_on_container_swap::value} \end{itemize} is \tcode{true} within the implementation of the corresponding \tcode{polymorphic} operation. \pnum A program that instantiates the definition of \tcode{polymorphic} for a non-object type, an array type, \tcode{in_place_t}, a specialization of \tcode{in_place_type_t}, or a cv-qualified type is ill-formed. \pnum The template parameter \tcode{T} of \tcode{polymorphic} may be an incomplete type. \pnum The template parameter \tcode{Allocator} of \tcode{polymorphic} shall meet the requirements of \oldconcept{Allocator}. \pnum If a program declares an explicit or partial specialization of \tcode{polymorphic}, the behavior is undefined. \rSec3[polymorphic.syn]{Synopsis} \indexlibraryglobal{polymorphic}% \begin{codeblock} namespace std { template> class polymorphic { public: using value_type = T; using allocator_type = Allocator; using pointer = allocator_traits::pointer; using const_pointer = allocator_traits::const_pointer; // \ref{polymorphic.ctor}, constructors constexpr explicit polymorphic(); constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); constexpr polymorphic(const polymorphic& other); constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other); constexpr polymorphic(polymorphic&& other) noexcept; constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) noexcept(@\seebelow@); template constexpr explicit polymorphic(U&& u); template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u); template constexpr explicit polymorphic(in_place_type_t, Ts&&... ts); template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, Ts&&... ts); template constexpr explicit polymorphic(in_place_type_t, initializer_list ilist, Us&&... us); template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, initializer_list ilist, Us&&... us); // \ref{polymorphic.dtor}, destructor constexpr ~polymorphic(); // \ref{polymorphic.assign}, assignment constexpr polymorphic& operator=(const polymorphic& other); constexpr polymorphic& operator=(polymorphic&& other) noexcept(@\seebelow@); // \ref{polymorphic.obs}, observers constexpr const T& operator*() const noexcept; constexpr T& operator*() noexcept; constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept; constexpr bool valueless_after_move() const noexcept; constexpr allocator_type get_allocator() const noexcept; // \ref{polymorphic.swap}, swap constexpr void swap(polymorphic& other) noexcept(@\seebelow@); friend constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(@\seebelow@); private: Allocator @\exposid{alloc}@ = Allocator(); // \expos }; } \end{codeblock} \rSec3[polymorphic.ctor]{Constructors} \pnum The following element applies to all functions in~\ref{polymorphic.ctor}: \begin{itemdescr} \pnum \throws Nothing unless \tcode{allocator_traits::allocate} or \tcode{allocator_traits::construct} throws. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr explicit polymorphic(); \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_default_constructible_v} is \tcode{true}. \pnum \mandates \begin{itemize} \item \tcode{is_default_constructible_v} is \tcode{true}, and \item \tcode{is_copy_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{T} with an empty argument list using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr explicit polymorphic(allocator_arg_t, const Allocator& a); \end{itemdecl} \begin{itemdescr} \pnum \mandates \begin{itemize} \item \tcode{is_default_constructible_v} is \tcode{true}, and \item \tcode{is_copy_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{T} with an empty argument list using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr polymorphic(const polymorphic& other); \end{itemdecl} \begin{itemdescr} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{allocator_traits::select_on_contai\-ner_copy_construction(other.\exposid{alloc})}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, constructs an owned object of type \tcode{U}, where \tcode{U} is the type of the owned object in \tcode{other}, with the owned object in \tcode{other} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr polymorphic(allocator_arg_t, const Allocator& a, const polymorphic& other); \end{itemdecl} \begin{itemdescr} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, constructs an owned object of type \tcode{U}, where \tcode{U} is the type of the owned object in \tcode{other}, with the owned object in \tcode{other} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr polymorphic(polymorphic&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{std::move(other.\exposid{alloc})}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, either \tcode{*this} takes ownership of the owned object of \tcode{other} or, %FIXME: Cleanup awkward wording. owns an object of the same type constructed from the owned object of \tcode{other} considering that owned object as an rvalue, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} constexpr polymorphic(allocator_arg_t, const Allocator& a, polymorphic&& other) noexcept(allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. If \tcode{other} is valueless, \tcode{*this} is valueless. Otherwise, if \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, either constructs an object of type \tcode{polymorphic} that owns the owned object of \tcode{other}, making \tcode{other} valueless; or, %FIXME: Cleanup awkward wording. (And similar wording elsewhere). owns an object of the same type constructed from the owned object of \tcode{other} considering that owned object as an rvalue. Otherwise, if \tcode{\exposid{alloc} != other.\exposid{alloc}} is \tcode{true}, constructs an owned object of type \tcode{U}, where \tcode{U} is the type of the owned object in \tcode{other}, with the owned object in \tcode{other} as an rvalue, using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(U&& u); \end{itemdecl} \begin{itemdescr} \pnum \constraints Where \tcode{UU} is \tcode{remove_cvref_t}, \begin{itemize} \item \tcode{is_same_v} is \tcode{false}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v} is \tcode{true}, \item \tcode{is_copy_constructible_v} is \tcode{true}, \item \tcode{UU} is not a specialization of \tcode{in_place_type_t}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{UU} with \tcode{std::forward(u)} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, U&& u); \end{itemdecl} \begin{itemdescr} \pnum \constraints Where \tcode{UU} is \tcode{remove_cvref_t}, \begin{itemize} \item \tcode{is_same_v} is \tcode{false}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v} is \tcode{true}, \item \tcode{is_copy_constructible_v} is \tcode{true}, and \item \tcode{UU} is not a specialization of \tcode{in_place_type_t}. \end{itemize} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{UU} with \tcode{std::forward(u)} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(in_place_type_t, Ts&&... ts); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, U>} is \tcode{true}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v} is \tcode{true}, \item \tcode{is_copy_constructible_v} is \tcode{true}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{U} with \tcode{std::forward(ts)...} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, Ts&&... ts); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, U>} is \tcode{true}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v} is \tcode{true}, and \item \tcode{is_copy_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{U} with \tcode{std::forward(ts)...} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(in_place_type_t, initializer_list ilist, Us&&... us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, U>} is \tcode{true}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v\&, Us...>} is \tcode{true}, \item \tcode{is_copy_constructible_v} is \tcode{true}, and \item \tcode{is_default_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects Constructs an owned object of type \tcode{U} with the arguments \tcode{ilist, std::forward(us)...} using the allocator \exposid{alloc}. \end{itemdescr} \indexlibraryctor{polymorphic}% \begin{itemdecl} template constexpr explicit polymorphic(allocator_arg_t, const Allocator& a, in_place_type_t, initializer_list ilist, Us&&... us); \end{itemdecl} \begin{itemdescr} \pnum \constraints \begin{itemize} \item \tcode{is_same_v, U>} is \tcode{true}, \item \tcode{derived_from} is \tcode{true}, \item \tcode{is_constructible_v\&, Us...>} is \tcode{true}, and \item \tcode{is_copy_constructible_v} is \tcode{true}. \end{itemize} \pnum \effects \exposid{alloc} is direct-non-list-initialized with \tcode{a}. Constructs an owned object of type \tcode{U} with the arguments \tcode{ilist, std::forward(us)...} using the allocator \exposid{alloc}. \end{itemdescr} \rSec3[polymorphic.dtor]{Destructor} \indexlibrarydtor{polymorphic}% \begin{itemdecl} constexpr ~polymorphic(); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type. \pnum \effects If \tcode{*this} is not valueless, calls \tcode{allocator_traits::destroy(p)}, where \tcode{p} is a pointer of type \tcode{U*} to the owned object and \tcode{U} is the type of the owned object; then the storage is deallocated. \end{itemdescr} \rSec3[polymorphic.assign]{Assignment} \indexlibrarymember{operator=}{polymorphic}% \indexlibrarydtor{polymorphic}% \begin{itemdecl} constexpr polymorphic& operator=(const polymorphic& other); \end{itemdecl} \begin{itemdescr} \pnum \mandates \tcode{T} is a complete type. \pnum \effects If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item %FIXME: We're defining "allocator needs updating" as an effect? %FIXME: (Same issue as above) The allocator needs updating if \tcode{allocator_traits::propagate_on_contai\-ner_copy_assignment::value} is \tcode{true}. \item If \tcode{other} is not valueless, a new owned object of type \tcode{U}, where \tcode{U} is the type of the owned object in \tcode{other}, is constructed in \tcode{*this} using \tcode{allocator_traits::construct} with the owned object from \tcode{other} as the argument, using either the allocator in \tcode{*this} or the allocator in \tcode{other} if the allocator needs updating. \item The previously owned object in \tcode{*this}, if any, is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and then the storage is deallocated. \item If the allocator needs updating, the allocator in \tcode{*this} is replaced with a copy of the allocator in \tcode{other}. \end{itemize} \pnum \returns A reference to \tcode{*this}. \pnum \remarks If any exception is thrown, there are no effects on \tcode{*this}. \end{itemdescr} \indexlibrarymember{operator=}{polymorphic}% \begin{itemdecl} constexpr polymorphic& operator=(polymorphic&& other) noexcept(allocator_traits::propagate_on_container_move_assignment::value || allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \mandates If \tcode{allocator_traits::propagate_on_container_move_assignment::val\-ue} is \tcode{false} and \tcode{allocator_traits::is_always_equal::value} is \tcode{false}, \tcode{T} is a complete type. \pnum \effects If \tcode{addressof(other) == this} is \tcode{true}, there are no effects. Otherwise: \begin{itemize} \item %FIXME: We're defining "allocator needs updating" as an effect? %FIXME: (Same issue as above) The allocator needs updating if \tcode{allocator_traits::propagate_on_container_move_assignment::value} is \tcode{true}. \item If \tcode{other} is valueless, \tcode{*this} becomes valueless. \item Otherwise, if the allocator needs updating or \tcode{\exposid{alloc} == other.\exposid{alloc}} is \tcode{true}, \tcode{*this} takes ownership of the owned object of \tcode{other}. \item Otherwise, constructs a new owned object of type \tcode{U}, where \tcode{U} is the type of the owned object in \tcode{other}, with the owned object of \tcode{other} as the argument as an rvalue, using the allocator in \tcode{*this}. \item The previously owned object in \tcode{*this}, if any, is destroyed using \tcode{allocator_traits::\linebreak{}destroy} and then the storage is deallocated. \item If the allocator needs updating, the allocator in \tcode{*this} is replaced with a copy of the allocator in \tcode{other}. \end{itemize} \pnum \returns A reference to \tcode{*this}. \pnum \remarks If any exception is thrown, there are no effects on \tcode{*this} or \tcode{other}. \end{itemdescr} \rSec3[polymorphic.obs]{Observers} \indexlibrarymember{operator*}{polymorphic}% \begin{itemdecl} constexpr const T& operator*() const noexcept; constexpr T& operator*() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not valueless. \pnum \returns A reference to the owned object. \end{itemdescr} \indexlibrarymember{operator->}{polymorphic}% \begin{itemdecl} constexpr const_pointer operator->() const noexcept; constexpr pointer operator->() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{*this} is not valueless. \pnum \returns A pointer to the owned object. \end{itemdescr} \indexlibrarymember{valueless_after_move}{polymorphic}% \begin{itemdecl} constexpr bool valueless_after_move() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{true} if \tcode{*this} is valueless, otherwise \tcode{false}. \end{itemdescr} \indexlibrarymember{get_allocator}{polymorphic}% \begin{itemdecl} constexpr allocator_type get_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \exposid{alloc}. \end{itemdescr} \rSec3[polymorphic.swap]{Swap} \indexlibrarymember{swap}{polymorphic}% \begin{itemdecl} constexpr void swap(polymorphic& other) noexcept(allocator_traits::propagate_on_container_swap::value || allocator_traits::is_always_equal::value); \end{itemdecl} \begin{itemdescr} \pnum \expects If \tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true}, then \tcode{Allocator} meets the \oldconcept{Swappable} requirements. Otherwise \tcode{get_allocator() == other.\linebreak{}get_allocator()} is \tcode{true}. \pnum \effects Swaps the states of \tcode{*this} and \tcode{other}, exchanging owned objects or valueless states. If \tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true}, then the allocators of \tcode{*this} and \tcode{other} are exchanged by calling \tcode{swap} as described in~\ref{swappable.requirements}. Otherwise, the allocators are not swapped. \begin{note} Does not call \tcode{swap} on the owned objects directly. \end{note} \end{itemdescr} \indexlibrarymember{swap}{polymorphic}% %FIXME: "friend" included on declaration in synopsis but not here. \begin{itemdecl} constexpr void swap(polymorphic& lhs, polymorphic& rhs) noexcept(noexcept(lhs.swap(rhs))); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{lhs.swap(rhs)}. \end{itemdescr} \rSec1[mem.res]{Memory resources} \rSec2[mem.res.syn]{Header \tcode{} synopsis} \indexheader{memory_resource}% \begin{codeblock} namespace std::pmr { // \ref{mem.res.class}, class \tcode{memory_resource} class memory_resource; bool operator==(const memory_resource& a, const memory_resource& b) noexcept; // \ref{mem.poly.allocator.class}, class template \tcode{polymorphic_allocator} template class polymorphic_allocator; template bool operator==(const polymorphic_allocator& a, const polymorphic_allocator& b) noexcept; // \ref{mem.res.global}, global memory resources memory_resource* new_delete_resource() noexcept; memory_resource* null_memory_resource() noexcept; memory_resource* set_default_resource(memory_resource* r) noexcept; memory_resource* get_default_resource() noexcept; // \ref{mem.res.pool}, pool resource classes struct pool_options; class synchronized_pool_resource; class unsynchronized_pool_resource; class monotonic_buffer_resource; } \end{codeblock} \rSec2[mem.res.class]{Class \tcode{memory_resource}} \rSec3[mem.res.class.general]{General} \pnum The \tcode{memory_resource} class is an abstract interface to an unbounded set of classes encapsulating memory resources. \indexlibraryglobal{memory_resource}% \indexlibrarymember{operator=}{memory_resource}% \begin{codeblock} namespace std::pmr { class memory_resource { static constexpr size_t max_align = alignof(max_align_t); // \expos public: memory_resource() = default; memory_resource(const memory_resource&) = default; virtual ~memory_resource(); memory_resource& operator=(const memory_resource&) = default; void* allocate(size_t bytes, size_t alignment = max_align); void deallocate(void* p, size_t bytes, size_t alignment = max_align); bool is_equal(const memory_resource& other) const noexcept; private: virtual void* do_allocate(size_t bytes, size_t alignment) = 0; virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; }; } \end{codeblock} \rSec3[mem.res.public]{Public member functions} \indexlibrarydtor{memory_resource}% \begin{itemdecl} ~memory_resource(); \end{itemdecl} \begin{itemdescr} \pnum \effects Destroys this \tcode{memory_resource}. \end{itemdescr} \indexlibrarymember{allocate}{memory_resource}% \begin{itemdecl} void* allocate(size_t bytes, size_t alignment = max_align); \end{itemdecl} \begin{itemdescr} \pnum \effects Allocates storage by calling \tcode{do_allocate(bytes, alignment)} and implicitly creates objects within the allocated region of storage. \pnum \returns A pointer to a suitable created object\iref{intro.object} in the allocated region of storage. \pnum \throws What and when the call to \tcode{do_allocate} throws. \end{itemdescr} \indexlibrarymember{deallocate}{memory_resource}% \begin{itemdecl} void deallocate(void* p, size_t bytes, size_t alignment = max_align); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{do_deallocate(p, bytes, alignment)}. \end{itemdescr} \indexlibrarymember{is_equal}{memory_resource}% \begin{itemdecl} bool is_equal(const memory_resource& other) const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return do_is_equal(other);} \end{itemdescr} \rSec3[mem.res.private]{Private virtual member functions} \indexlibrarymember{do_allocate}{memory_resource}% \begin{itemdecl} virtual void* do_allocate(size_t bytes, size_t alignment) = 0; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{alignment} is a power of two. \pnum \returns A derived class shall implement this function to return a pointer to allocated storage\iref{basic.stc.dynamic.allocation} with a size of at least \tcode{bytes}, aligned to the specified \tcode{alignment}. \pnum \throws A derived class implementation shall throw an appropriate exception if it is unable to allocate memory with the requested size and alignment. \end{itemdescr} \indexlibrarymember{do_deallocate}{memory_resource}% \begin{itemdecl} virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0; \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{p} was returned from a prior call to \tcode{allocate(bytes, alignment)} on a memory resource equal to \tcode{*this}, and the storage at \tcode{p} has not yet been deallocated. \pnum \effects A derived class shall implement this function to dispose of allocated storage. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{do_is_equal}{memory_resource}% \begin{itemdecl} virtual bool do_is_equal(const memory_resource& other) const noexcept = 0; \end{itemdecl} \begin{itemdescr} \pnum \returns A derived class shall implement this function to return \tcode{true} if memory allocated from \tcode{*this} can be deallocated from \tcode{other} and vice-versa, otherwise \tcode{false}. \begin{note} It is possible that the most-derived type of \tcode{other} does not match the type of \tcode{*this}. For a derived class \tcode{D}, an implementation of this function can immediately return \tcode{false} if \tcode{dynamic_cast(\&other) == nullptr}. \end{note} \end{itemdescr} \rSec3[mem.res.eq]{Equality} \indexlibrarymember{operator==}{memory_resource}% \begin{itemdecl} bool operator==(const memory_resource& a, const memory_resource& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{\&a == \&b || a.is_equal(b)}. \end{itemdescr} \rSec2[mem.poly.allocator.class]{Class template \tcode{polymorphic_allocator}} \rSec3[mem.poly.allocator.class.general]{General} \pnum A specialization of class template \tcode{pmr::polymorphic_allocator} meets the \oldconcept{Allocator} requirements\iref{allocator.requirements.general} if its template argument is a \cv-unqualified object type. Constructed with different memory resources, different instances of the same specialization of \tcode{pmr::polymorphic_allocator} can exhibit entirely different allocation behavior. This runtime polymorphism allows objects that use \tcode{polymorphic_allocator} to behave as if they used different allocator types at run time even though they use the same static allocator type. \pnum A specialization of class template \tcode{pmr::polymorphic_allocator} meets the allocator completeness requirements\iref{allocator.requirements.completeness} if its template argument is a \cv-unqualified object type. \indexlibraryglobal{polymorphic_allocator}% \indexlibrarymember{value_type}{polymorphic_allocator}% \begin{codeblock} namespace std::pmr { template class polymorphic_allocator { memory_resource* memory_rsrc; // \expos public: using value_type = Tp; // \ref{mem.poly.allocator.ctor}, constructors polymorphic_allocator() noexcept; polymorphic_allocator(memory_resource* r); polymorphic_allocator(const polymorphic_allocator& other) = default; template polymorphic_allocator(const polymorphic_allocator& other) noexcept; polymorphic_allocator& operator=(const polymorphic_allocator&) = delete; // \ref{mem.poly.allocator.mem}, member functions Tp* allocate(size_t n); void deallocate(Tp* p, size_t n); void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); template T* allocate_object(size_t n = 1); template void deallocate_object(T* p, size_t n = 1); template T* new_object(CtorArgs&&... ctor_args); template void delete_object(T* p); template void construct(T* p, Args&&... args); template void destroy(T* p); polymorphic_allocator select_on_container_copy_construction() const; memory_resource* resource() const; // friends friend bool operator==(const polymorphic_allocator& a, const polymorphic_allocator& b) noexcept { return *a.resource() == *b.resource(); } }; } \end{codeblock} \rSec3[mem.poly.allocator.ctor]{Constructors} \indexlibraryctor{polymorphic_allocator}% \begin{itemdecl} polymorphic_allocator() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Sets \tcode{memory_rsrc} to \tcode{get_default_resource()}. \end{itemdescr} \indexlibraryctor{polymorphic_allocator}% \begin{itemdecl} polymorphic_allocator(memory_resource* r); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{r} is non-null. \pnum \effects Sets \tcode{memory_rsrc} to \tcode{r}. \pnum \throws Nothing. \pnum \begin{note} This constructor provides an implicit conversion from \tcode{memory_resource*}. \end{note} \end{itemdescr} \indexlibraryctor{polymorphic_allocator}% \begin{itemdecl} template polymorphic_allocator(const polymorphic_allocator& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Sets \tcode{memory_rsrc} to \tcode{other.resource()}. \end{itemdescr} \rSec3[mem.poly.allocator.mem]{Member functions} \indexlibrarymember{allocate}{polymorphic_allocator}% \begin{itemdecl} Tp* allocate(size_t n); \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{numeric_limits::max() / sizeof(Tp) < n}, throws \tcode{bad_array_new_length}. Otherwise equivalent to: \begin{codeblock} return static_cast(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp))); \end{codeblock} \end{itemdescr} \indexlibrarymember{deallocate}{polymorphic_allocator}% \begin{itemdecl} void deallocate(Tp* p, size_t n); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{p} was allocated from a memory resource \tcode{x}, equal to \tcode{*memory_rsrc}, using \tcode{x.allocate(n * sizeof(Tp), alignof(Tp))}. \pnum \effects Equivalent to \tcode{memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp))}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{allocate_bytes}{polymorphic_allocator}% \begin{itemdecl} void* allocate_bytes(size_t nbytes, size_t alignment = alignof(max_align_t)); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \tcode{return memory_rsrc->allocate(nbytes, alignment);} \pnum \begin{note} The return type is \tcode{void*} (rather than, e.g., \tcode{byte*}) to support conversion to an arbitrary pointer type \tcode{U*} by \tcode{static_cast}, thus facilitating construction of a \tcode{U} object in the allocated memory. \end{note} \end{itemdescr} \indexlibrarymember{deallocate_bytes}{polymorphic_allocator}% \begin{itemdecl} void deallocate_bytes(void* p, size_t nbytes, size_t alignment = alignof(max_align_t)); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{memory_rsrc->deallocate(p, nbytes, alignment)}. \end{itemdescr} \indexlibrarymember{allocate_object}{polymorphic_allocator}% \begin{itemdecl} template T* allocate_object(size_t n = 1); \end{itemdecl} \begin{itemdescr} \pnum \effects Allocates memory suitable for holding an array of \tcode{n} objects of type \tcode{T}, as follows: \begin{itemize} \item if \tcode{numeric_limits::max() / sizeof(T) < n}, throws \tcode{bad_array_new_length}, \item otherwise equivalent to: \begin{codeblock} return static_cast(allocate_bytes(n*sizeof(T), alignof(T))); \end{codeblock} \end{itemize} \pnum \begin{note} \tcode{T} is not deduced and must therefore be provided as a template argument. \end{note} \end{itemdescr} \indexlibrarymember{deallocate_object}{polymorphic_allocator}% \begin{itemdecl} template void deallocate_object(T* p, size_t n = 1); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{deallocate_bytes(p, n*sizeof(T), alignof(T))}. \end{itemdescr} \indexlibrarymember{new_object}{polymorphic_allocator}% \begin{itemdecl} template T* new_object(CtorArgs&&... ctor_args); \end{itemdecl} \begin{itemdescr} \pnum \effects Allocates and constructs an object of type \tcode{T}, as follows.\newline Equivalent to: \begin{codeblock} T* p = allocate_object(); try { construct(p, std::forward(ctor_args)...); } catch (...) { deallocate_object(p); throw; } return p; \end{codeblock} \pnum \begin{note} \tcode{T} is not deduced and must therefore be provided as a template argument. \end{note} \end{itemdescr} \indexlibrarymember{new_object}{polymorphic_allocator}% \begin{itemdecl} template void delete_object(T* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} destroy(p); deallocate_object(p); \end{codeblock} \end{itemdescr} \indexlibrarymember{construct}{polymorphic_allocator}% \begin{itemdecl} template void construct(T* p, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \mandates Uses-allocator construction of \tcode{T} with allocator \tcode{*this} (see~\ref{allocator.uses.construction}) and constructor arguments \tcode{std::forward(args)...} is well-formed. \pnum \effects Constructs a \tcode{T} object in the storage whose address is represented by \tcode{p} by uses-allocator construction with allocator \tcode{*this} and constructor arguments \tcode{std::forward(args)...}. \pnum \throws Nothing unless the constructor for \tcode{T} throws. \end{itemdescr} \indexlibrarymember{destroy}{polymorphic_allocator}% \begin{itemdecl} template void destroy(T* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to \tcode{p->\~T()}. \end{itemdescr} \indexlibrarymember{select_on_container_copy_construction}{polymorphic_allocator}% \begin{itemdecl} polymorphic_allocator select_on_container_copy_construction() const; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{polymorphic_allocator()}. \pnum \begin{note} The memory resource is not propagated. \end{note} \end{itemdescr} \indexlibrarymember{resource}{polymorphic_allocator}% \begin{itemdecl} memory_resource* resource() const; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{memory_rsrc}. \end{itemdescr} \rSec3[mem.poly.allocator.eq]{Equality} \indexlibrarymember{operator==}{polymorphic_allocator}% \begin{itemdecl} template bool operator==(const polymorphic_allocator& a, const polymorphic_allocator& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{*a.resource() == *b.resource()}. \end{itemdescr} \rSec2[mem.res.global]{Access to program-wide \tcode{memory_resource} objects} \indexlibraryglobal{new_delete_resource}% \begin{itemdecl} memory_resource* new_delete_resource() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A pointer to a static-duration object of a type derived from \tcode{memory_resource} that can serve as a resource for allocating memory using \tcode{::operator new} and \tcode{::operator delete}. The same value is returned every time this function is called. For a return value \tcode{p} and a memory resource \tcode{r}, \tcode{p->is_equal(r)} returns \tcode{\&r == p}. \end{itemdescr} \indexlibraryglobal{null_memory_resource}% \begin{itemdecl} memory_resource* null_memory_resource() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns A pointer to a static-duration object of a type derived from \tcode{memory_resource} for which \tcode{allocate()} always throws \tcode{bad_alloc} and for which \tcode{deallocate()} has no effect. The same value is returned every time this function is called. For a return value \tcode{p} and a memory resource \tcode{r}, \tcode{p->is_equal(r)} returns \tcode{\&r == p}. \end{itemdescr} \pnum The \defn{default memory resource pointer} is a pointer to a memory resource that is used by certain facilities when an explicit memory resource is not supplied through the interface. Its initial value is the return value of \tcode{new_delete_resource()}. \indexlibraryglobal{set_default_resource}% \begin{itemdecl} memory_resource* set_default_resource(memory_resource* r) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects If \tcode{r} is non-null, sets the value of the default memory resource pointer to \tcode{r}, otherwise sets the default memory resource pointer to \tcode{new_delete_resource()}. \pnum \returns The previous value of the default memory resource pointer. \pnum \remarks Calling the \tcode{set_default_resource} and \tcode{get_default_resource} functions shall not incur a data race\iref{intro.races}. A call to the \tcode{set_default_resource} function synchronizes with subsequent calls to the \tcode{set_default_resource} and \tcode{get_default_resource} functions. \end{itemdescr} \indexlibraryglobal{get_default_resource}% \begin{itemdecl} memory_resource* get_default_resource() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns The current value of the default memory resource pointer. \end{itemdescr} \rSec2[mem.res.pool]{Pool resource classes} \rSec3[mem.res.pool.overview]{Classes \tcode{synchronized_pool_resource} and \tcode{unsynchronized_pool_resource}} \pnum The \tcode{synchronized_pool_resource} and \tcode{unsynchronized_pool_resource} classes (collectively called \defn{pool resource classes}) are general-purpose memory resources having the following qualities: \begin{itemize} \item Each resource frees its allocated memory on destruction, even if \tcode{deallocate} has not been called for some of the allocated blocks. \item A pool resource consists of a collection of \defn{pools}, serving requests for different block sizes. Each individual pool manages a collection of \defn{chunks} that are in turn divided into blocks of uniform size, returned via calls to \tcode{do_allocate}. Each call to \tcode{do_allocate(size, alignment)} is dispatched to the pool serving the smallest blocks accommodating at least \tcode{size} bytes. \item When a particular pool is exhausted, allocating a block from that pool results in the allocation of an additional chunk of memory from the \defn{upstream allocator} (supplied at construction), thus replenishing the pool. With each successive replenishment, the chunk size obtained increases geometrically. \begin{note} By allocating memory in chunks, the pooling strategy increases the chance that consecutive allocations will be close together in memory. \end{note} \item Allocation requests that exceed the largest block size of any pool are fulfilled directly from the upstream allocator. \item A \tcode{pool_options} struct may be passed to the pool resource constructors to tune the largest block size and the maximum chunk size. \end{itemize} \pnum A \tcode{synchronized_pool_resource} may be accessed from multiple threads without external synchronization and may have thread-specific pools to reduce synchronization costs. An \tcode{unsynchronized_pool_resource} class may not be accessed from multiple threads simultaneously and thus avoids the cost of synchronization entirely in single-threaded applications. \indexlibraryglobal{pool_options}% \indexlibraryglobal{synchronized_pool_resource}% \indexlibraryglobal{unsynchronized_pool_resource}% \begin{codeblock} namespace std::pmr { struct pool_options { size_t max_blocks_per_chunk = 0; size_t largest_required_pool_block = 0; }; class synchronized_pool_resource : public memory_resource { public: synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); synchronized_pool_resource() : synchronized_pool_resource(pool_options(), get_default_resource()) {} explicit synchronized_pool_resource(memory_resource* upstream) : synchronized_pool_resource(pool_options(), upstream) {} explicit synchronized_pool_resource(const pool_options& opts) : synchronized_pool_resource(opts, get_default_resource()) {} synchronized_pool_resource(const synchronized_pool_resource&) = delete; virtual ~synchronized_pool_resource(); synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete; void release(); memory_resource* upstream_resource() const; pool_options options() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; class unsynchronized_pool_resource : public memory_resource { public: unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource() : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} explicit unsynchronized_pool_resource(memory_resource* upstream) : unsynchronized_pool_resource(pool_options(), upstream) {} explicit unsynchronized_pool_resource(const pool_options& opts) : unsynchronized_pool_resource(opts, get_default_resource()) {} unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; virtual ~unsynchronized_pool_resource(); unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete; void release(); memory_resource* upstream_resource() const; pool_options options() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; } \end{codeblock} \rSec3[mem.res.pool.options]{\tcode{pool_options} data members} \pnum The members of \tcode{pool_options} comprise a set of constructor options for pool resources. The effect of each option on the pool resource behavior is described below: \indexlibrarymember{pool_options}{max_blocks_per_chunk}% \begin{itemdecl} size_t max_blocks_per_chunk; \end{itemdecl} \begin{itemdescr} \pnum The maximum number of blocks that will be allocated at once from the upstream memory resource\iref{mem.res.monotonic.buffer} to replenish a pool. If the value of \tcode{max_blocks_per_chunk} is zero or is greater than an \impldef{largest supported value to configure the maximum number of blocks to replenish a pool} limit, that limit is used instead. The implementation may choose to use a smaller value than is specified in this member and may use different values for different pools. \end{itemdescr} \indexlibrarymember{pool_options}{largest_required_pool_block}% \begin{itemdecl} size_t largest_required_pool_block; \end{itemdecl} \begin{itemdescr} \pnum The largest allocation size that is required to be fulfilled using the pooling mechanism. Attempts to allocate a single block larger than this threshold will be allocated directly from the upstream memory resource. If \tcode{largest_required_pool_block} is zero or is greater than an \impldef{largest supported value to configure the largest allocation satisfied directly by a pool} limit, that limit is used instead. The implementation may choose a pass-through threshold larger than specified in this member. \end{itemdescr} \rSec3[mem.res.pool.ctor]{Constructors and destructors} \indexlibraryctor{synchronized_pool_resource}% \indexlibraryctor{unsynchronized_pool_resource}% \begin{itemdecl} synchronized_pool_resource(const pool_options& opts, memory_resource* upstream); unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{upstream} is the address of a valid memory resource. \pnum \effects Constructs a pool resource object that will obtain memory from \tcode{upstream} whenever the pool resource is unable to satisfy a memory request from its own internal data structures. The resulting object will hold a copy of \tcode{upstream}, but will not own the resource to which \tcode{upstream} points. \begin{note} The intention is that calls to \tcode{upstream->allocate()} will be substantially fewer than calls to \tcode{this->allocate()} in most cases. \end{note} The behavior of the pooling mechanism is tuned according to the value of the \tcode{opts} argument. \pnum \throws Nothing unless \tcode{upstream->allocate()} throws. It is unspecified if, or under what conditions, this constructor calls \tcode{upstream->allocate()}. \end{itemdescr} \indexlibrarydtor{synchronized_pool_resource}% \indexlibrarydtor{unsynchronized_pool_resource}% \begin{itemdecl} virtual ~synchronized_pool_resource(); virtual ~unsynchronized_pool_resource(); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{release()}. \end{itemdescr} \rSec3[mem.res.pool.mem]{Members} \indexlibrarymember{release}{synchronized_pool_resource}% \indexlibrarymember{release}{unsynchronized_pool_resource}% \begin{itemdecl} void release(); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{upstream_resource()->deallocate()} as necessary to release all allocated memory. \begin{note} The memory is released back to \tcode{upstream_resource()} even if \tcode{deallocate} has not been called for some of the allocated blocks. \end{note} \end{itemdescr} \indexlibrarymember{upstream_resource}{synchronized_pool_resource}% \indexlibrarymember{upstream_resource}{unsynchronized_pool_resource}% \begin{itemdecl} memory_resource* upstream_resource() const; \end{itemdecl} \begin{itemdescr} \pnum \returns The value of the \tcode{upstream} argument provided to the constructor of this object. \end{itemdescr} \indexlibrarymember{options}{synchronized_pool_resource}% \indexlibrarymember{options}{unsynchronized_pool_resource}% \begin{itemdecl} pool_options options() const; \end{itemdecl} \begin{itemdescr} \pnum \returns The options that control the pooling behavior of this resource. The values in the returned struct may differ from those supplied to the pool resource constructor in that values of zero will be replaced with \impldef{default configuration of a pool} defaults, and sizes may be rounded to unspecified granularity. \end{itemdescr} \indexlibrarymember{do_allocate}{synchronized_pool_resource}% \indexlibrarymember{do_allocate}{unsynchronized_pool_resource}% \begin{itemdecl} void* do_allocate(size_t bytes, size_t alignment) override; \end{itemdecl} \begin{itemdescr} \pnum \effects If the pool selected for a block of size \tcode{bytes} is unable to satisfy the memory request from its own internal data structures, it will call \tcode{upstream_resource()->allocate()} to obtain more memory. If \tcode{bytes} is larger than that which the largest pool can handle, then memory will be allocated using \tcode{upstream_resource()->allocate()}. \pnum \returns A pointer to allocated storage\iref{basic.stc.dynamic.allocation} with a size of at least \tcode{bytes}. The size and alignment of the allocated memory shall meet the requirements for a class derived from \tcode{memory_resource}\iref{mem.res.class}. \pnum \throws Nothing unless \tcode{upstream_resource()->allocate()} throws. \end{itemdescr} \indexlibrarymember{do_deallocate}{synchronized_pool_resource}% \indexlibrarymember{do_deallocate}{unsynchronized_pool_resource}% \begin{itemdecl} void do_deallocate(void* p, size_t bytes, size_t alignment) override; \end{itemdecl} \begin{itemdescr} \pnum \effects Returns the memory at \tcode{p} to the pool. It is unspecified if, or under what circumstances, this operation will result in a call to \tcode{upstream_resource()->deallocate()}. \pnum \throws Nothing. \end{itemdescr} \indexlibrarymember{do_is_equal}{synchronized_pool_resource}% \indexlibrarymember{do_is_equal}{unsynchronized_pool_resource}% \begin{itemdecl} bool do_is_equal(const memory_resource& other) const noexcept override; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{this == \&other}. \end{itemdescr} \rSec2[mem.res.monotonic.buffer]{Class \tcode{monotonic_buffer_resource}} \rSec3[mem.res.monotonic.buffer.general]{General} \pnum A \tcode{monotonic_buffer_resource} is a special-purpose memory resource intended for very fast memory allocations in situations where memory is used to build up a few objects and then is released all at once when the memory resource object is destroyed. \indexlibraryglobal{monotonic_buffer_resource}% \begin{codeblock} namespace std::pmr { class monotonic_buffer_resource : public memory_resource { memory_resource* upstream_rsrc; // \expos void* current_buffer; // \expos size_t next_buffer_size; // \expos public: explicit monotonic_buffer_resource(memory_resource* upstream); monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); monotonic_buffer_resource() : monotonic_buffer_resource(get_default_resource()) {} explicit monotonic_buffer_resource(size_t initial_size) : monotonic_buffer_resource(initial_size, get_default_resource()) {} monotonic_buffer_resource(void* buffer, size_t buffer_size) : monotonic_buffer_resource(buffer, buffer_size, get_default_resource()) {} monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; virtual ~monotonic_buffer_resource(); monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; void release(); memory_resource* upstream_resource() const; protected: void* do_allocate(size_t bytes, size_t alignment) override; void do_deallocate(void* p, size_t bytes, size_t alignment) override; bool do_is_equal(const memory_resource& other) const noexcept override; }; } \end{codeblock} \rSec3[mem.res.monotonic.buffer.ctor]{Constructors and destructor} \indexlibraryctor{monotonic_buffer_resource}% \begin{itemdecl} explicit monotonic_buffer_resource(memory_resource* upstream); monotonic_buffer_resource(size_t initial_size, memory_resource* upstream); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{upstream} is the address of a valid memory resource. \tcode{initial_size}, if specified, is greater than zero. \pnum \effects Sets \tcode{upstream_rsrc} to \tcode{upstream} and \tcode{current_buffer} to \keyword{nullptr}. If \tcode{initial_size} is specified, sets \tcode{next_buffer_size} to at least \tcode{initial_size}; otherwise sets \tcode{next_buffer_size} to an \impldef{default \tcode{next_buffer_size} for a \tcode{monotonic_buffer_resource}} size. \end{itemdescr} \indexlibraryctor{monotonic_buffer_resource}% \begin{itemdecl} monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream); \end{itemdecl} \begin{itemdescr} \pnum \expects \tcode{upstream} is the address of a valid memory resource. \tcode{buffer_size} is no larger than the number of bytes in \tcode{buffer}. \pnum \effects Sets \tcode{upstream_rsrc} to \tcode{upstream}, \tcode{current_buffer} to \tcode{buffer}, and \tcode{next_buffer_size} to \tcode{buffer_size} (but not less than 1), then increases \tcode{next_buffer_size} by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral). \end{itemdescr} \indexlibrarydtor{monotonic_buffer_resource}% \begin{itemdecl} ~monotonic_buffer_resource(); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{release()}. \end{itemdescr} \rSec3[mem.res.monotonic.buffer.mem]{Members} \indexlibrarymember{release}{monotonic_buffer_resource}% \begin{itemdecl} void release(); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{upstream_rsrc->deallocate()} as necessary to release all allocated memory. Resets \tcode{current_buffer} and \tcode{next_buffer_size} to their initial values at construction. \pnum \begin{note} The memory is released back to \tcode{upstream_rsrc} even if some blocks that were allocated from \tcode{*this} have not been deallocated from \tcode{*this}. \end{note} \end{itemdescr} \indexlibrarymember{upstream_resource}{monotonic_buffer_resource}% \begin{itemdecl} memory_resource* upstream_resource() const; \end{itemdecl} \begin{itemdescr} \pnum \returns The value of \tcode{upstream_rsrc}. \end{itemdescr} \indexlibrarymember{do_allocate}{monotonic_buffer_resource}% \begin{itemdecl} void* do_allocate(size_t bytes, size_t alignment) override; \end{itemdecl} \begin{itemdescr} \pnum \effects If the unused space in \tcode{current_buffer} can fit a block with the specified \tcode{bytes} and \tcode{alignment}, then allocate the return block from \tcode{current_buffer}; otherwise set \tcode{current_buffer} to \tcode{upstream_rsrc->allocate(n, m)}, where \tcode{n} is not less than \tcode{max(bytes, next_buffer_size)} and \tcode{m} is not less than \tcode{alignment}, and increase \tcode{next_buffer_size} by an \impldef{growth factor for \tcode{monotonic_buffer_resource}} growth factor (which need not be integral), then allocate the return block from the newly-allocated \tcode{current_buffer}. \pnum \returns A pointer to allocated storage\iref{basic.stc.dynamic.allocation} with a size of at least \tcode{bytes}. The size and alignment of the allocated memory shall meet the requirements for a class derived from \tcode{memory_resource}\iref{mem.res.class}. \pnum \throws Nothing unless \tcode{upstream_rsrc->allocate()} throws. \end{itemdescr} \indexlibrarymember{do_deallocate}{monotonic_buffer_resource}% \begin{itemdecl} void do_deallocate(void* p, size_t bytes, size_t alignment) override; \end{itemdecl} \begin{itemdescr} \pnum \effects None. \pnum \throws Nothing. \pnum \remarks Memory used by this resource increases monotonically until its destruction. \end{itemdescr} \indexlibrarymember{do_is_equal}{monotonic_buffer_resource}% \begin{itemdecl} bool do_is_equal(const memory_resource& other) const noexcept override; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{this == \&other}. \end{itemdescr} \rSec1[allocator.adaptor]{Class template \tcode{scoped_allocator_adaptor}} \rSec2[allocator.adaptor.syn]{Header \tcode{} synopsis} \indexheader{scoped_allocator}% \begin{codeblock} namespace std { // class template \tcode{scoped_allocator_adaptor} template class scoped_allocator_adaptor; // \ref{scoped.adaptor.operators}, scoped allocator operators template bool operator==(const scoped_allocator_adaptor& a, const scoped_allocator_adaptor& b) noexcept; } \end{codeblock} \pnum The class template \tcode{scoped_allocator_adaptor} is an allocator template that specifies an allocator resource (the outer allocator) to be used by a container (as any other allocator does) and also specifies an inner allocator resource to be passed to the constructor of every element within the container. This adaptor is instantiated with one outer and zero or more inner allocator types. If instantiated with only one allocator type, the inner allocator becomes the \tcode{scoped_allocator_adaptor} itself, thus using the same allocator resource for the container and every element within the container and, if the elements themselves are containers, each of their elements recursively. If instantiated with more than one allocator, the first allocator is the outer allocator for use by the container, the second allocator is passed to the constructors of the container's elements, and, if the elements themselves are containers, the third allocator is passed to the elements' elements, and so on. If containers are nested to a depth greater than the number of allocators, the last allocator is used repeatedly, as in the single-allocator case, for any remaining recursions. \begin{note} The \tcode{scoped_allocator_adaptor} is derived from the outer allocator type so it can be substituted for the outer allocator type in most expressions. \end{note} \indexlibraryglobal{scoped_allocator_adaptor}% \indexlibrarymember{outer_allocator_type}{scoped_allocator_adaptor}% \indexlibrarymember{value_type}{scoped_allocator_adaptor}% \indexlibrarymember{size_type}{scoped_allocator_adaptor}% \indexlibrarymember{difference_type}{scoped_allocator_adaptor}% \indexlibrarymember{pointer}{scoped_allocator_adaptor}% \indexlibrarymember{const_pointer}{scoped_allocator_adaptor}% \indexlibrarymember{void_pointer}{scoped_allocator_adaptor}% \indexlibrarymember{const_void_pointer}{scoped_allocator_adaptor}% \begin{codeblock} namespace std { template class scoped_allocator_adaptor : public OuterAlloc { private: using OuterTraits = allocator_traits; // \expos scoped_allocator_adaptor inner; // \expos public: using outer_allocator_type = OuterAlloc; using inner_allocator_type = @\seebelow@; using value_type = OuterTraits::value_type; using size_type = OuterTraits::size_type; using difference_type = OuterTraits::difference_type; using pointer = OuterTraits::pointer; using const_pointer = OuterTraits::const_pointer; using void_pointer = OuterTraits::void_pointer; using const_void_pointer = OuterTraits::const_void_pointer; using propagate_on_container_copy_assignment = @\seebelow@; using propagate_on_container_move_assignment = @\seebelow@; using propagate_on_container_swap = @\seebelow@; using is_always_equal = @\seebelow@; template struct rebind { using other = scoped_allocator_adaptor< OuterTraits::template rebind_alloc, InnerAllocs...>; }; scoped_allocator_adaptor(); template scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; template scoped_allocator_adaptor( const scoped_allocator_adaptor& other) noexcept; template scoped_allocator_adaptor( scoped_allocator_adaptor&& other) noexcept; scoped_allocator_adaptor& operator=(const scoped_allocator_adaptor&) = default; scoped_allocator_adaptor& operator=(scoped_allocator_adaptor&&) = default; ~scoped_allocator_adaptor(); inner_allocator_type& inner_allocator() noexcept; const inner_allocator_type& inner_allocator() const noexcept; outer_allocator_type& outer_allocator() noexcept; const outer_allocator_type& outer_allocator() const noexcept; pointer allocate(size_type n); pointer allocate(size_type n, const_void_pointer hint); void deallocate(pointer p, size_type n); size_type max_size() const; template void construct(T* p, Args&&... args); template void destroy(T* p); scoped_allocator_adaptor select_on_container_copy_construction() const; }; template scoped_allocator_adaptor(OuterAlloc, InnerAllocs...) -> scoped_allocator_adaptor; } \end{codeblock} \rSec2[allocator.adaptor.types]{Member types} \indexlibrarymember{inner_allocator_type}{scoped_allocator_adaptor}% \begin{itemdecl} using inner_allocator_type = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{scoped_allocator_adaptor} if \tcode{sizeof...(InnerAllocs)} is zero; otherwise,\\ \tcode{scoped_allocator_adaptor}. \end{itemdescr} \indexlibrarymember{propagate_on_container_copy_assignment}{scoped_allocator_adaptor}% \begin{itemdecl} using propagate_on_container_copy_assignment = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{true_type} if \tcode{allocator_traits::propagate_on_container_copy_assignment::value} is \tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and \tcode{InnerAllocs...}; otherwise, \tcode{false_type}. \end{itemdescr} \indexlibrarymember{propagate_on_container_move_assignment}{scoped_allocator_adaptor}% \begin{itemdecl} using propagate_on_container_move_assignment = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{true_type} if \tcode{allocator_traits::propagate_on_container_move_assignment::value} is \tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and \tcode{InnerAllocs...}; otherwise, \tcode{false_type}. \end{itemdescr} \indexlibrarymember{propagate_on_container_swap}{scoped_allocator_adaptor}% \begin{itemdecl} using propagate_on_container_swap = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{true_type} if \tcode{allocator_traits::propagate_on_container_swap::value} is \tcode{true} for any \tcode{A} in the set of \tcode{OuterAlloc} and \tcode{InnerAllocs...}; otherwise, \tcode{false_type}. \end{itemdescr} \indexlibrarymember{is_always_equal}{scoped_allocator_adaptor}% \begin{itemdecl} using is_always_equal = @\seebelow@; \end{itemdecl} \begin{itemdescr} \pnum \ctype \tcode{true_type} if \tcode{allocator_traits::is_always_equal::value} is \tcode{true} for every \tcode{A} in the set of \tcode{OuterAlloc} and \tcode{InnerAllocs...}; otherwise, \tcode{false_type}. \end{itemdescr} \rSec2[allocator.adaptor.cnstr]{Constructors} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} scoped_allocator_adaptor(); \end{itemdecl} \begin{itemdescr} \pnum \effects Value-initializes the \tcode{OuterAlloc} base class and the \tcode{inner} allocator object. \end{itemdescr} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} template scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v} is \tcode{true}. \pnum \effects Initializes the \tcode{OuterAlloc} base class with \tcode{std::forward(outerAlloc)} and \tcode{inner} with \tcode{innerAllocs...} (hence recursively initializing each allocator within the adaptor with the corresponding allocator from the argument list). \end{itemdescr} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Initializes each allocator within the adaptor with the corresponding allocator from \tcode{other}. \end{itemdescr} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects Move constructs each allocator within the adaptor with the corresponding allocator from \tcode{other}. \end{itemdescr} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} template scoped_allocator_adaptor( const scoped_allocator_adaptor& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v} is \tcode{true}. \pnum \effects Initializes each allocator within the adaptor with the corresponding allocator from \tcode{other}. \end{itemdescr} \indexlibraryctor{scoped_allocator_adaptor}% \begin{itemdecl} template scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \constraints \tcode{is_constructible_v} is \tcode{true}. \pnum \effects Initializes each allocator within the adaptor with the corresponding allocator rvalue from \tcode{other}. \end{itemdescr} \rSec2[allocator.adaptor.members]{Members} \pnum In the \tcode{construct} member functions, \tcode{\placeholdernc{OUTERMOST}(x)} is \tcode{\placeholdernc{OUTERMOST}(x.outer_allocator())} if the expression \tcode{x.outer_allocator()} is valid~\iref{temp.deduct} and \tcode{x} otherwise; \tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(x)} is \tcode{allocator_traits>}. \begin{note} \tcode{\placeholdernc{OUTERMOST}(x)} and \tcode{\placeholdernc{OUTERMOST_ALL\-OC_TRAITS}(x)} are recursive operations. It is incumbent upon the definition of \tcode{outer_allocator()} to ensure that the recursion terminates. It will terminate for all instantiations of \tcode{scoped_allocator_adaptor}. \end{note} \indexlibrarymember{inner_allocator}{scoped_allocator_adaptor}% \begin{itemdecl} inner_allocator_type& inner_allocator() noexcept; const inner_allocator_type& inner_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{*this} if \tcode{sizeof...(InnerAllocs)} is zero; otherwise, \tcode{inner}. \end{itemdescr} \indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% \begin{itemdecl} outer_allocator_type& outer_allocator() noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{static_cast(*this)}. \end{itemdescr} \indexlibrarymember{outer_allocator}{scoped_allocator_adaptor}% \begin{itemdecl} const outer_allocator_type& outer_allocator() const noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{static_cast(*this)}. \end{itemdescr} \indexlibrarymember{allocate}{scoped_allocator_adaptor}% \begin{itemdecl} pointer allocate(size_type n); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{allocator_traits::allocate(outer_allocator(), n)}. \end{itemdescr} \indexlibrarymember{allocate}{scoped_allocator_adaptor}% \begin{itemdecl} pointer allocate(size_type n, const_void_pointer hint); \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{allocator_traits::allocate(outer_allocator(), n, hint)}. \end{itemdescr} \indexlibrarymember{deallocate}{scoped_allocator_adaptor}% \begin{itemdecl} void deallocate(pointer p, size_type n) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \effects As if by: \tcode{allocator_traits::deallocate(outer_allocator(), p, n);} \end{itemdescr} \indexlibrarymember{max_size}{scoped_allocator_adaptor}% \begin{itemdecl} size_type max_size() const; \end{itemdecl} \begin{itemdescr} \pnum \returns \tcode{allocator_traits::max_size(outer_allocator())}. \end{itemdescr} \indexlibrarymember{construct}{scoped_allocator_adaptor}% \begin{itemdecl} template void construct(T* p, Args&&... args); \end{itemdecl} \begin{itemdescr} \pnum \effects Equivalent to: \begin{codeblock} apply([p, this](auto&&... newargs) { @\placeholdernc{OUTERMOST_ALLOC_TRAITS}@(*this)::construct( @\placeholdernc{OUTERMOST}@(*this), p, std::forward(newargs)...); }, uses_allocator_construction_args(inner_allocator(), std::forward(args)...)); \end{codeblock} \end{itemdescr} \indexlibrarymember{destroy}{scoped_allocator_adaptor}% \begin{itemdecl} template void destroy(T* p); \end{itemdecl} \begin{itemdescr} \pnum \effects Calls \tcode{\placeholdernc{OUTERMOST_ALLOC_TRAITS}(*this)::destroy(\placeholdernc{OUTERMOST}(*this), p)}. \end{itemdescr} \indexlibrarymember{select_on_container_copy_construction}{scoped_allocator_adaptor}% \begin{itemdecl} scoped_allocator_adaptor select_on_container_copy_construction() const; \end{itemdecl} \begin{itemdescr} \pnum \returns A new \tcode{scoped_allocator_adaptor} object where each allocator \tcode{a1} within the adaptor is initialized with \tcode{allocator_traits::select_on_container_copy_construction(a2)}, where \tcode{A1} is the type of \tcode{a1} and \tcode{a2} is the corresponding allocator in \tcode{*this}. \end{itemdescr} \rSec2[scoped.adaptor.operators]{Operators} \indexlibrarymember{operator==}{scoped_allocator_adaptor}% \begin{itemdecl} template bool operator==(const scoped_allocator_adaptor& a, const scoped_allocator_adaptor& b) noexcept; \end{itemdecl} \begin{itemdescr} \pnum \returns If \tcode{sizeof...(InnerAllocs)} is zero, \begin{codeblock} a.outer_allocator() == b.outer_allocator() \end{codeblock} otherwise \begin{codeblock} a.outer_allocator() == b.outer_allocator() && a.inner_allocator() == b.inner_allocator() \end{codeblock} \end{itemdescr}