Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 20

 

  Главная      Manuals     Working Draft, Standard for Programming Language C++ (N4713, 2017 year)

 

Search            copyright infringement  

 

 

 

 

 

 

 

 

 

 

 

Content      ..     18      19      20      21     ..

 

 

 

Working Draft, Standard for Programming Language C++ (N4713, 2017 year) - page 20

 

 

};
}
1
An exception of type bad_weak_ptr is thrown by the shared_ptr constructor taking a weak_ptr.
bad_weak_ptr() noexcept;
2
Postconditions: what() returns an implementation-defined ntbs.
23.11.3
Class template shared_ptr
[util.smartptr.shared]
1
The shared_ptr class template stores a pointer, usually obtained via new. 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 shared_ptr is said to be empty if it
does not own a pointer.
namespace std {
template<class T> class shared_ptr {
public:
using element_type = remove_extent_t<T>;
using weak_type
= weak_ptr<T>;
// 23.11.3.1, constructors
constexpr shared_ptr() noexcept;
constexpr shared_ptr(nullptr_t) noexcept : shared_ptr() { }
template<class Y>
explicit shared_ptr(Y* p);
template<class Y, class D>
shared_ptr(Y* p, D d);
template<class Y, class D, class A>
shared_ptr(Y* p, D d, A a);
template<class D>
shared_ptr(nullptr_t p, D d);
template<class D, class A>
shared_ptr(nullptr_t p, D d, A a);
template<class Y>
shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
shared_ptr(const shared_ptr& r) noexcept;
template<class Y>
shared_ptr(const shared_ptr<Y>& r) noexcept;
shared_ptr(shared_ptr&& r) noexcept;
template<class Y>
shared_ptr(shared_ptr<Y>&& r) noexcept;
template<class Y>
explicit shared_ptr(const weak_ptr<Y>& r);
template<class Y, class D>
shared_ptr(unique_ptr<Y, D>&& r);
// 23.11.3.2, destructor
~shared_ptr();
// 23.11.3.3, assignment
shared_ptr& operator=(const shared_ptr& r) noexcept;
template<class Y>
shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
shared_ptr& operator=(shared_ptr&& r) noexcept;
template<class Y>
shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
template<class Y, class D>
shared_ptr& operator=(unique_ptr<Y, D>&& r);
// 23.11.3.4, modifiers
void swap(shared_ptr& r) noexcept;
void reset() noexcept;
template<class Y>
void reset(Y* p);
§
23.11.3
562
template<class Y, class D>
void reset(Y* p, D d);
template<class Y, class D, class A>
void reset(Y* p, D d, A a);
// 23.11.3.5, observers
element_type* get() const noexcept;
T& operator*() const noexcept;
T* operator->() const noexcept;
element_type& operator[](ptrdiff_t i) const;
long use_count() const noexcept;
explicit operator bool() const noexcept;
template<class U>
bool owner_before(const shared_ptr<U>& b) const noexcept;
template<class U>
bool owner_before(const weak_ptr<U>& b) const noexcept;
};
template<class T>
shared_ptr(weak_ptr<T>) -> shared_ptr<T>;
template<class T, class D>
shared_ptr(unique_ptr<T, D>) -> shared_ptr<T>;
}
2
Specializations of shared_ptr shall be CopyConstructible, CopyAssignable, and LessThanComparable,
allowing their use in standard containers. Specializations of shared_ptr shall be contextually convertible to
bool, allowing their use in boolean expressions and declarations in conditions. The template parameter T of
shared_ptr may be an incomplete type.
3
[ Example:
if (shared_ptr<X> px = dynamic_pointer_cast<X>(py)) {
// do something with px
}
— end example ]
4
For purposes of determining the presence of a data race, member functions shall access and modify only the
shared_ptr and weak_ptr objects themselves and not objects they refer to. Changes in use_count() do
not reflect modifications that can introduce data races.
5
For the purposes of subclause 23.11, a pointer type Y* is said to be compatible with a pointer type T* when
either Y* is convertible to T* or Y is U[N] and T is cv U[].
23.11.3.1
shared_ptr constructors
[util.smartptr.shared.const]
1
In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means
that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_-
this (23.11.6), then remove_cv_t<Y>* shall be implicitly convertible to T* and the constructor evaluates
the statement:
if (p != nullptr && p->weak_this.expired())
p->weak_this = shared_ptr<remove_cv_t<Y>>(*this, const_cast<remove_cv_t<Y>*>(p));
The assignment to the weak_this member is not atomic and conflicts with any potentially concurrent access
to the same object (6.8.2).
constexpr shared_ptr() noexcept;
2
Effects: Constructs an empty shared_ptr object.
3
Postconditions: use_count() == 0 && get() == nullptr.
template<class Y> explicit shared_ptr(Y* p);
4
Requires: Y shall be a complete type. The expression delete[] p, when T is an array type, or delete
p, when T is not an array type, shall have well-defined behavior, and shall not throw exceptions.
5
Effects: When T is not an array type, constructs a shared_ptr object that owns the pointer p. Otherwise,
constructs a shared_ptr that owns p and a deleter of an unspecified type that calls delete[] p. When
§ 23.11.3.1
563
T is not an array type, enables shared_from_this with p. If an exception is thrown, delete p is called
when T is not an array type, delete[] p otherwise.
6
Postconditions: use_count() == 1 && get() == p.
7
Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could
not be obtained.
8
Remarks: When T is an array type, this constructor shall not participate in overload resolution unless
the expression delete[] p is well-formed and either T is U[N] and Y(*)[N] is convertible to T*, or T is
U[] and Y(*)[] is convertible to T*. When T is not an array type, this constructor shall not participate
in overload resolution unless the expression delete p is well-formed and Y* is convertible to T*.
template<class Y, class D> shared_ptr(Y* p, D d);
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D> shared_ptr(nullptr_t p, D d);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
9
Requires: Construction of d and a deleter of type D initialized with std::move(d) shall not throw
exceptions. The expression d(p) shall have well-defined behavior and shall not throw exceptions. A
shall be an allocator (20.5.3.5).
10
Effects: Constructs a shared_ptr object that owns the object p and the deleter d. When T is not an
array type, the first and second constructors enable shared_from_this with p. The second and fourth
constructors shall use a copy of a to allocate memory for internal use. If an exception is thrown, d(p)
is called.
11
Postconditions: use_count() == 1 && get() == p.
12
Throws: bad_alloc, or an implementation-defined exception when a resource other than memory could
not be obtained.
13
Remarks: When T is an array type, this constructor shall not participate in overload resolution unless
is_move_constructible_v<D> is true, the expression d(p) is well-formed, and either T is U[N] and
Y(*)[N] is convertible to T*, or T is U[] and Y(*)[] is convertible to T*. When T is not an array type,
this constructor shall not participate in overload resolution unless is_move_constructible_v<D> is
true, the expression d(p) is well-formed, and Y* is convertible to T*.
template<class Y> shared_ptr(const shared_ptr<Y>& r, element_type* p) noexcept;
14
Effects: Constructs a shared_ptr instance that stores p and shares ownership with r.
15
Postconditions: get() == p && use_count() == r.use_count().
16
[ Note: To avoid the possibility of a dangling pointer, the user of this constructor should ensure that p
remains valid at least until the ownership group of r is destroyed.
— end note ]
17
[ Note: This constructor allows creation of an empty shared_ptr instance with a non-null stored pointer.
— end note ]
shared_ptr(const shared_ptr& r) noexcept;
template<class Y> shared_ptr(const shared_ptr<Y>& r) noexcept;
18
Remarks: The second constructor shall not participate in overload resolution unless Y* is compatible
with T*.
19
Effects: If r is empty, constructs an empty shared_ptr object; otherwise, constructs a shared_ptr
object that shares ownership with r.
20
Postconditions: get() == r.get() && use_count() == r.use_count().
shared_ptr(shared_ptr&& r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y>&& r) noexcept;
21
Remarks: The second constructor shall not participate in overload resolution unless Y* is compatible
with T*.
22
Effects: Move constructs a shared_ptr instance from r.
23
Postconditions: *this shall contain the old value of r. r shall be empty. r.get() == nullptr.
§ 23.11.3.1
564
template<class Y> explicit shared_ptr(const weak_ptr<Y>& r);
24
Effects: Constructs a shared_ptr object that shares ownership with r and stores a copy of the pointer
stored in r. If an exception is thrown, the constructor has no effect.
25
Postconditions: use_count() == r.use_count().
26
Throws: bad_weak_ptr when r.expired().
27
Remarks: This constructor shall not participate in overload resolution unless Y* is compatible with T*.
template<class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
28
Remarks: This constructor shall not participate in overload resolution unless Y* is compatible with T*
and unique_ptr<Y, D>::pointer is convertible to element_type*.
29
Effects: If r.get() == nullptr, equivalent to shared_ptr(). Otherwise, if D is not a reference
type, equivalent to shared_ptr(r.release(), r.get_deleter()). Otherwise, equivalent to shared_-
ptr(r.release(), ref(r.get_deleter())). If an exception is thrown, the constructor has no effect.
23.11.3.2
shared_ptr destructor
[util.smartptr.shared.dest]
~shared_ptr();
1
Effects:
(1.1)
If
*this is empty or shares ownership with another shared_ptr instance (use_count() > 1),
there are no side effects.
(1.2)
Otherwise, if *this owns an object p and a deleter d, d(p) is called.
(1.3)
Otherwise, *this owns a pointer p, and delete p is called.
2
[ Note: Since the destruction of *this decreases the number of instances that share ownership with *this by
one, after *this has been destroyed all shared_ptr instances that shared ownership with *this will report
a use_count() that is one less than its previous value.
— end note ]
23.11.3.3
shared_ptr assignment
[util.smartptr.shared.assign]
shared_ptr& operator=(const shared_ptr& r) noexcept;
template<class Y> shared_ptr& operator=(const shared_ptr<Y>& r) noexcept;
1
Effects: Equivalent to shared_ptr(r).swap(*this).
2
Returns: *this.
3
[Note: The use count updates caused by the temporary object construction and destruction are not
observable side effects, so the implementation may meet the effects (and the implied guarantees) via
different means, without creating a temporary. In particular, in the example:
shared_ptr<int> p(new int);
shared_ptr<void> q(p);
p = p;
q = p;
both assignments may be no-ops.
— end note ]
shared_ptr& operator=(shared_ptr&& r) noexcept;
template<class Y> shared_ptr& operator=(shared_ptr<Y>&& r) noexcept;
4
Effects: Equivalent to shared_ptr(std::move(r)).swap(*this).
5
Returns: *this.
template<class Y, class D> shared_ptr& operator=(unique_ptr<Y, D>&& r);
6
Effects: Equivalent to shared_ptr(std::move(r)).swap(*this).
7
Returns: *this.
23.11.3.4
shared_ptr modifiers
[util.smartptr.shared.mod]
void swap(shared_ptr& r) noexcept;
1
Effects: Exchanges the contents of *this and r.
§ 23.11.3.4
565
void reset() noexcept;
2
Effects: Equivalent to shared_ptr().swap(*this).
template<class Y> void reset(Y* p);
3
Effects: Equivalent to shared_ptr(p).swap(*this).
template<class Y, class D> void reset(Y* p, D d);
4
Effects: Equivalent to shared_ptr(p, d).swap(*this).
template<class Y, class D, class A> void reset(Y* p, D d, A a);
5
Effects: Equivalent to shared_ptr(p, d, a).swap(*this).
23.11.3.5
shared_ptr observers
[util.smartptr.shared.obs]
element_type* get() const noexcept;
1
Returns: The stored pointer.
T& operator*() const noexcept;
2
Requires: get() != 0.
3
Returns: *get().
4
Remarks: When T is an array type or cv 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.
T* operator->() const noexcept;
5
Requires: get() != 0.
6
Returns: get().
7
Remarks: When 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.
element_type& operator[](ptrdiff_t i) const;
8
Requires: get() != 0 && i >= 0. If T is U[N], i < N.
9
Returns: get()[i].
10
Remarks: When 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.
11
Throws: Nothing.
long use_count() const noexcept;
12
Returns: The number of shared_ptr objects, *this included, that share ownership with *this, or 0
when *this is empty.
13
Synchronization: None.
14
[ Note: get() == nullptr does not imply a specific return value of use_count().
— end note ]
15
[ Note: weak_ptr<T>::lock() can affect the return value of use_count().
— end note ]
16
[ Note: When multiple threads can affect the return value of use_count(), the result should be treated
as approximate. In particular, use_count() == 1 does not imply that accesses through a previously
destroyed shared_ptr have in any sense completed.
— end note ]
explicit operator bool() const noexcept;
17
Returns: get() != 0.
template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept;
template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept;
18
Returns: An unspecified value such that
§ 23.11.3.5
566
(18.1)
x.owner_before(y) defines a strict weak ordering as defined in 28.7;
(18.2)
under the equivalence relation defined by owner_before, !a.owner_before(b) && !b.owner_-
before(a), two shared_ptr or weak_ptr instances are equivalent if and only if they share
ownership or are both empty.
23.11.3.6
shared_ptr creation
[util.smartptr.shared.create]
1
The common requirements that apply to all make_shared and allocate_shared overloads, unless specified
otherwise, are described below.
template<class T, ...>
shared_ptr<T> make_shared(args);
template<class T, class A, ...>
shared_ptr<T> allocate_shared(const A& a, args);
2
Requires: A shall be an allocator (20.5.3.5).
3
Effects: Allocates memory for an object of type T (or U[N] when T is U[], where N is determined
from args as specified by the concrete overload). The object is initialized from args as specified by
the concrete overload. The allocate_shared templates use a copy of a (rebound for an unspecified
value_type) to allocate memory. If an exception is thrown, the functions have no effect.
4
Returns: A shared_ptr instance that stores and owns the address of the newly constructed object.
5
Postconditions: r.get() != 0 && r.use_count() == 1, where r is the return value.
6
Throws: bad_alloc, or an exception thrown from allocate or from the initialization of the object.
7
Remarks:
(7.1)
Implementations should perform no more than one memory allocation.
[Note: This provides
efficiency equivalent to an intrusive smart pointer.
— end note ]
(7.2)
When an object of an array type U is specified to have an initial value of 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 u.
(7.3)
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.
(7.4)
When a (sub)object of a non-array type U is specified to have an initial value of v, or U(l...),
where l... is a list of constructor arguments, make_shared shall initialize this (sub)object via
the expression ::new(pv) U(v) or ::new(pv) U(l...) respectively, where pv has type void*
and points to storage suitable to hold an object of type U.
(7.5)
When a (sub)object of a non-array type U is specified to have an initial value of v, or U(l...),
where l... is a list of constructor arguments, allocate_shared shall initialize this (sub)object
via the expression
(7.5.1)
allocator_traits<A2>::construct(a2, pv, v) or
(7.5.2)
allocator_traits<A2>::construct(a2, pv, l...)
respectively, where pv points to storage suitable to hold an object of type U and a2 of type A2 is a
rebound copy of the allocator a passed to allocate_shared such that its value_type is U.
(7.6)
When a (sub)object of non-array type U is specified to have a default initial value, make_shared
shall initialize this (sub)object via the expression ::new(pv) U(), where pv has type void* and
points to storage suitable to hold an object of type U.
(7.7)
When a (sub)object of non-array type U is specified to have a default initial value, allocate_shared
shall initialize this (sub)object via the expression allocator_traits<A2>::construct(a2, pv),
where pv points to storage suitable to hold an object of type U and a2 of type A2 is a rebound
copy of the allocator a passed to allocate_shared such that its value_type is U.
(7.8)
Array elements are initialized in ascending order of their addresses.
(7.9)
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 should be destroyed in the reverse
order of their construction.
§ 23.11.3.6
567
[Note: These functions will typically allocate more memory than sizeof(T) to allow for internal
bookkeeping structures such as reference counts.
— end note ]
template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args);
// T is not array
template<class T, class A, class... Args>
shared_ptr<T> allocate_shared(const A& a, Args&&... args);
// T is not array
8
Returns: A shared_ptr to an object of type T with an initial value T(forward<Args>(args)...).
9
Remarks: These overloads shall only participate in overload resolution when T is not an array type.
The shared_ptr constructors called by these functions enable shared_from_this with the address of
the newly constructed object of type T.
10
[ Example:
shared_ptr<int> p = make_shared<int>(); // shared_ptr to int()
shared_ptr<vector<int>> q = make_shared<vector<int>>(16, 1);
// shared_ptr to vector of 16 elements with value 1
— end example ]
template<class T> shared_ptr<T>
make_shared(size_t N);
// T is U[]
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, size_t N);
// T is U[]
11
Returns: A shared_ptr to an object of type U[N] with a default initial value, where U is remove_-
extent_t<T>.
12
Remarks: These overloads shall only participate in overload resolution when T is of the form U[].
13
[ Example:
shared_ptr<double[]> p = make_shared<double[]>(1024);
// shared_ptr to a value-initialized double[1024]
shared_ptr<double[][2][2]> q = make_shared<double[][2][2]>(6);
// shared_ptr to a value-initialized double[6][2][2]
— end example ]
template<class T>
shared_ptr<T> make_shared();
// T is U[N]
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a);
// T is U[N]
14
Returns: A shared_ptr to an object of type T with a default initial value.
15
Remarks: These overloads shall only participate in overload resolution when T is of the form U[N].
16
[ Example:
shared_ptr<double[1024]> p = make_shared<double[1024]>();
// shared_ptr to a value-initialized double[1024]
shared_ptr<double[6][2][2]> q = make_shared<double[6][2][2]>();
// shared_ptr to a value-initialized double[6][2][2]
— end example ]
template<class T>
shared_ptr<T> make_shared(size_t N,
const remove_extent_t<T>& u);
// T is U[]
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, size_t N,
const remove_extent_t<T>& u);
// T is U[]
17
Returns: A shared_ptr to an object of type U[N], where U is remove_extent_t<T> and each array
element has an initial value of u.
18
Remarks: These overloads shall only participate in overload resolution when T is of the form U[].
19
[ Example:
shared_ptr<double[]> p = make_shared<double[]>(1024, 1.0);
§ 23.11.3.6
568
// shared_ptr to a double[1024], where each element is 1.0
shared_ptr<double[][2]> q = make_shared<double[][2]>(6, {1.0, 0.0});
// shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}
shared_ptr<vector<int>[]> r = make_shared<vector<int>[]>(4, {1, 2});
// shared_ptr to a vector<int>[4], where each vector has contents {1, 2}
— end example ]
template<class T>
shared_ptr<T> make_shared(const remove_extent_t<T>& u);
// T is U[N]
template<class T, class A>
shared_ptr<T> allocate_shared(const A& a,
const remove_extent_t<T>& u);
// T is U[N]
20
Returns: A shared_ptr to an object of type T, where each array element of type remove_extent_t<T>
has an initial value of u.
21
Remarks: These overloads shall only participate in overload resolution when T is of the form U[N].
22
[ Example:
shared_ptr<double[1024]> p = make_shared<double[1024]>(1.0);
// shared_ptr to a double[1024], where each element is 1.0
shared_ptr<double[6][2]> q = make_shared<double[6][2]>({1.0, 0.0});
// shared_ptr to a double[6][2], where each double[2] element is {1.0, 0.0}
shared_ptr<vector<int>[4]> r = make_shared<vector<int>[4]>({1, 2});
// shared_ptr to a vector<int>[4], where each vector has contents {1, 2}
— end example ]
23.11.3.7
shared_ptr comparison
[util.smartptr.shared.cmp]
template<class T, class U>
bool operator==(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
1
Returns: a.get() == b.get().
template<class T, class U>
bool operator<(const shared_ptr<T>& a, const shared_ptr<U>& b) noexcept;
2
Returns: less<>()(a.get(), b.get()).
3
[Note: Defining a comparison function allows shared_ptr objects to be used as keys in associative
containers.
— end note ]
template<class T>
bool operator==(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator==(nullptr_t, const shared_ptr<T>& a) noexcept;
4
Returns: !a.
template<class T>
bool operator!=(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator!=(nullptr_t, const shared_ptr<T>& a) noexcept;
5
Returns: (bool)a.
template<class T>
bool operator<(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator<(nullptr_t, const shared_ptr<T>& a) noexcept;
6
Returns: The first function template returns
less<typename shared_ptr<T>::element_type*>()(a.get(), nullptr)
The second function template returns
less<typename shared_ptr<T>::element_type*>()(nullptr, a.get())
§ 23.11.3.7
569
template<class T>
bool operator>(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator>(nullptr_t, const shared_ptr<T>& a) noexcept;
7
Returns: The first function template returns nullptr < a. The second function template returns a <
nullptr.
template<class T>
bool operator<=(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator<=(nullptr_t, const shared_ptr<T>& a) noexcept;
8
Returns: The first function template returns !(nullptr < a). The second function template returns
!(a < nullptr).
template<class T>
bool operator>=(const shared_ptr<T>& a, nullptr_t) noexcept;
template<class T>
bool operator>=(nullptr_t, const shared_ptr<T>& a) noexcept;
9
Returns: The first function template returns !(a < nullptr). The second function template returns
!(nullptr < a).
23.11.3.8
shared_ptr specialized algorithms
[util.smartptr.shared.spec]
template<class T>
void swap(shared_ptr<T>& a, shared_ptr<T>& b) noexcept;
1
Effects: Equivalent to a.swap(b).
23.11.3.9
shared_ptr casts
[util.smartptr.shared.cast]
template<class T, class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r) noexcept;
1
Requires: The expression static_cast<T*>((U*)nullptr) shall be well-formed.
2
Returns:
shared_ptr<T>(r, static_cast<typename shared_ptr<T>::element_type*>(r.get()))
3
[Note: The seemingly equivalent expression shared_ptr<T>(static_cast<T*>(r.get())) will even-
tually result in undefined behavior, attempting to delete the same object twice.
— end note ]
template<class T, class U>
shared_ptr<T> dynamic_pointer_cast(const shared_ptr<U>& r) noexcept;
4
Requires: The expression dynamic_cast<T*>((U*)nullptr) shall be well-formed. The expression
dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()) shall be well formed and shall
have well-defined behavior.
5
Returns:
(5.1)
When dynamic_cast<typename shared_ptr<T>::element_type*>(r.get()) returns a non-null
value p, shared_ptr<T>(r, p).
(5.2)
Otherwise, shared_ptr<T>().
6
[ Note: The seemingly equivalent expression shared_ptr<T>(dynamic_cast<T*>(r.get())) will even-
tually result in undefined behavior, attempting to delete the same object twice.
— end note ]
template<class T, class U>
shared_ptr<T> const_pointer_cast(const shared_ptr<U>& r) noexcept;
7
Requires: The expression const_cast<T*>((U*)nullptr) shall be well-formed.
8
Returns:
shared_ptr<T>(r, const_cast<typename shared_ptr<T>::element_type*>(r.get()))
9
[ Note: The seemingly equivalent expression shared_ptr<T>(const_cast<T*>(r.get())) will eventu-
ally result in undefined behavior, attempting to delete the same object twice.
— end note ]
§ 23.11.3.9
570
template<class T, class U>
shared_ptr<T> reinterpret_pointer_cast(const shared_ptr<U>& r) noexcept;
10
Requires: The expression reinterpret_cast<T*>((U*)nullptr) shall be well-formed.
11
Returns:
shared_ptr<T>(r, reinterpret_cast<typename shared_ptr<T>::element_type*>(r.get()))
12
[ Note: The seemingly equivalent expression shared_ptr<T>(reinterpret_cast<T*>(r.get())) will
eventually result in undefined behavior, attempting to delete the same object twice.
— end note ]
23.11.3.10
get_deleter
[util.smartptr.getdeleter]
template<class D, class T>
D* get_deleter(const shared_ptr<T>& p) noexcept;
1
Returns: If p owns a deleter d of type cv-unqualified D, returns addressof(d); otherwise returns
nullptr. The returned pointer remains valid as long as there exists a shared_ptr instance that owns
d. [ 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 weak_ptr instances that share ownership with p
have been destroyed.
— end note ]
23.11.3.11
shared_ptr I/O
[util.smartptr.shared.io]
template<class E, class T, class Y>
basic_ostream<E, T>& operator<<(basic_ostream<E, T>& os, const shared_ptr<Y>& p);
1
Effects: As if by: os << p.get();
2
Returns: os.
23.11.4
Class template weak_ptr
[util.smartptr.weak]
1
The weak_ptr class template stores a weak reference to an object that is already managed by a shared_ptr.
To access the object, a weak_ptr can be converted to a shared_ptr using the member function lock.
namespace std {
template<class T> class weak_ptr {
public:
using element_type = remove_extent_t<T>;
// 23.11.4.1, constructors
constexpr weak_ptr() noexcept;
template<class Y>
weak_ptr(const shared_ptr<Y>& r) noexcept;
weak_ptr(const weak_ptr& r) noexcept;
template<class Y>
weak_ptr(const weak_ptr<Y>& r) noexcept;
weak_ptr(weak_ptr&& r) noexcept;
template<class Y>
weak_ptr(weak_ptr<Y>&& r) noexcept;
// 23.11.4.2, destructor
~weak_ptr();
// 23.11.4.3, assignment
weak_ptr& operator=(const weak_ptr& r) noexcept;
template<class Y>
weak_ptr& operator=(const weak_ptr<Y>& r) noexcept;
template<class Y>
weak_ptr& operator=(const shared_ptr<Y>& r) noexcept;
weak_ptr& operator=(weak_ptr&& r) noexcept;
template<class Y>
weak_ptr& operator=(weak_ptr<Y>&& r) noexcept;
// 23.11.4.4, modifiers
void swap(weak_ptr& r) noexcept;
void reset() noexcept;
§
23.11.4
571
// 23.11.4.5, observers
long use_count() const noexcept;
bool expired() const noexcept;
shared_ptr<T> lock() const noexcept;
template<class U>
bool owner_before(const shared_ptr<U>& b) const noexcept;
template<class U>
bool owner_before(const weak_ptr<U>& b) const noexcept;
};
template<class T>
weak_ptr(shared_ptr<T>) -> weak_ptr<T>;
// 23.11.4.6, specialized algorithms
template<class T>
void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;
}
2
Specializations of weak_ptr shall be CopyConstructible and CopyAssignable, allowing their use in standard
containers. The template parameter T of weak_ptr may be an incomplete type.
23.11.4.1
weak_ptr constructors
[util.smartptr.weak.const]
constexpr weak_ptr() noexcept;
1
Effects: Constructs an empty weak_ptr object.
2
Postconditions: use_count() == 0.
weak_ptr(const weak_ptr& r) noexcept;
template<class Y> weak_ptr(const weak_ptr<Y>& r) noexcept;
template<class Y> weak_ptr(const shared_ptr<Y>& r) noexcept;
3
Remarks: The second and third constructors shall not participate in overload resolution unless Y* is
compatible with T*.
4
Effects: If r is empty, constructs an empty weak_ptr object; otherwise, constructs a weak_ptr object
that shares ownership with r and stores a copy of the pointer stored in r.
5
Postconditions: use_count() == r.use_count().
weak_ptr(weak_ptr&& r) noexcept;
template<class Y> weak_ptr(weak_ptr<Y>&& r) noexcept;
6
Remarks: The second constructor shall not participate in overload resolution unless Y* is compatible
with T*.
7
Effects: Move constructs a weak_ptr instance from r.
8
Postconditions: *this shall contain the old value of r. r shall be empty. r.use_count() == 0.
23.11.4.2
weak_ptr destructor
[util.smartptr.weak.dest]
~weak_ptr();
1
Effects: Destroys this weak_ptr object but has no effect on the object its stored pointer points to.
23.11.4.3
weak_ptr assignment
[util.smartptr.weak.assign]
weak_ptr& operator=(const weak_ptr& r) noexcept;
template<class Y> weak_ptr& operator=(const weak_ptr<Y>& r) noexcept;
template<class Y> weak_ptr& operator=(const shared_ptr<Y>& r) noexcept;
1
Effects: Equivalent to weak_ptr(r).swap(*this).
2
Remarks: The implementation may meet the effects (and the implied guarantees) via different means,
without creating a temporary object.
3
Returns: *this.
§ 23.11.4.3
572
weak_ptr& operator=(weak_ptr&& r) noexcept;
template<class Y> weak_ptr& operator=(weak_ptr<Y>&& r) noexcept;
4
Effects: Equivalent to weak_ptr(std::move(r)).swap(*this).
5
Returns: *this.
23.11.4.4
weak_ptr modifiers
[util.smartptr.weak.mod]
void swap(weak_ptr& r) noexcept;
1
Effects: Exchanges the contents of *this and r.
void reset() noexcept;
2
Effects: Equivalent to weak_ptr().swap(*this).
23.11.4.5
weak_ptr observers
[util.smartptr.weak.obs]
long use_count() const noexcept;
1
Returns: 0 if *this is empty; otherwise, the number of shared_ptr instances that share ownership
with *this.
bool expired() const noexcept;
2
Returns: use_count() == 0.
shared_ptr<T> lock() const noexcept;
3
Returns: expired() ? shared_ptr<T>() : shared_ptr<T>(*this), executed atomically.
template<class U> bool owner_before(const shared_ptr<U>& b) const noexcept;
template<class U> bool owner_before(const weak_ptr<U>& b) const noexcept;
4
Returns: An unspecified value such that
(4.1)
x.owner_before(y) defines a strict weak ordering as defined in 28.7;
(4.2)
under the equivalence relation defined by owner_before, !a.owner_before(b) && !b.owner_-
before(a), two shared_ptr or weak_ptr instances are equivalent if and only if they share
ownership or are both empty.
23.11.4.6
weak_ptr specialized algorithms
[util.smartptr.weak.spec]
template<class T>
void swap(weak_ptr<T>& a, weak_ptr<T>& b) noexcept;
1
Effects: Equivalent to a.swap(b).
23.11.5
Class template owner_less
[util.smartptr.ownerless]
1
The class template owner_less allows ownership-based mixed comparisons of shared and weak pointers.
namespace std {
template<class T = void> struct owner_less;
template<class T> struct owner_less<shared_ptr<T>> {
bool operator()(const shared_ptr<T>&, const shared_ptr<T>&) const noexcept;
bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept;
bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept;
};
template<class T> struct owner_less<weak_ptr<T>> {
bool operator()(const weak_ptr<T>&, const weak_ptr<T>&) const noexcept;
bool operator()(const shared_ptr<T>&, const weak_ptr<T>&) const noexcept;
bool operator()(const weak_ptr<T>&, const shared_ptr<T>&) const noexcept;
};
template<> struct owner_less<void> {
template<class T, class U>
bool operator()(const shared_ptr<T>&, const shared_ptr<U>&) const noexcept;
§ 23.11.5
573
template<class T, class U>
bool operator()(const shared_ptr<T>&, const weak_ptr<U>&) const noexcept;
template<class T, class U>
bool operator()(const weak_ptr<T>&, const shared_ptr<U>&) const noexcept;
template<class T, class U>
bool operator()(const weak_ptr<T>&, const weak_ptr<U>&) const noexcept;
using is_transparent = unspecified ;
};
}
2
operator()(x, y) shall return x.owner_before(y). [ Note: Note that
(2.1)
operator() defines a strict weak ordering as defined in 28.7;
(2.2)
under the equivalence relation defined by operator(), !operator()(a, b) && !operator()(b, a),
two shared_ptr or weak_ptr instances are equivalent if and only if they share ownership or are both
empty.
— end note ]
23.11.6
Class template enable_shared_from_this
[util.smartptr.enab]
1
A class T can inherit from enable_shared_from_this<T> to inherit the shared_from_this member functions
that obtain a shared_ptr instance pointing to *this.
2
[ Example:
struct X: public enable_shared_from_this<X> { };
int main() {
shared_ptr<X> p(new X);
shared_ptr<X> q = p->shared_from_this();
assert(p == q);
assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership
}
— end example ]
namespace std {
template<class T> class enable_shared_from_this {
protected:
constexpr enable_shared_from_this() noexcept;
enable_shared_from_this(const enable_shared_from_this&) noexcept;
enable_shared_from_this& operator=(const enable_shared_from_this&) noexcept;
~enable_shared_from_this();
public:
shared_ptr<T> shared_from_this();
shared_ptr<T const> shared_from_this() const;
weak_ptr<T> weak_from_this() noexcept;
weak_ptr<T const> weak_from_this() const noexcept;
private:
mutable weak_ptr<T> weak_this;
// exposition only
};
}
3
The template parameter T of enable_shared_from_this may be an incomplete type.
constexpr enable_shared_from_this() noexcept;
enable_shared_from_this(const enable_shared_from_this<T>&) noexcept;
4
Effects: Value-initializes weak_this.
enable_shared_from_this<T>& operator=(const enable_shared_from_this<T>&) noexcept;
5
Returns: *this.
6
[ Note: weak_this is not changed.
— end note ]
§ 23.11.6
574
shared_ptr<T>
shared_from_this();
shared_ptr<T const> shared_from_this() const;
7
Returns: shared_ptr<T>(weak_this).
weak_ptr<T>
weak_from_this() noexcept;
weak_ptr<T const> weak_from_this() const noexcept;
8
Returns: weak_this.
23.11.7
Smart pointer hash support
[util.smartptr.hash]
template<class T, class D> struct hash<unique_ptr<T, D>>;
1
Letting UP be unique_ptr<T,D>, the specialization hash<UP> is enabled (23.14.15) if and only if
hash<typename UP::pointer> is enabled. When enabled, for an object p of type UP, hash<UP>()(p)
shall evaluate to the same value as hash<typename UP::pointer>()(p.get()). The member functions
are not guaranteed to be noexcept.
template<class T> struct hash<shared_ptr<T>>;
2
For an object p of type shared_ptr<T>, hash<shared_ptr<T>>()(p) shall evaluate to the same value
as hash<typename shared_ptr<T>::element_type*>()(p.get()).
23.11.8
Atomic specializations for smart pointers
[util.smartptr.atomic]
1
The library provides partial specializations of the atomic template for shared-ownership smart pointers. The
behavior of all operations is as specified in 32.6, unless specified otherwise. The template parameter T of
these partial specializations may be an incomplete type.
2
All changes to an atomic smart pointer in this subclause, and all associated use_count increments, are
guaranteed to be performed atomically. Associated use_count decrements are sequenced after the atomic
operation, but are not required to be part of it. Any associated deletion and deallocation are sequenced after
the atomic update step and are not part of the atomic operation. [ Note: If the atomic operation uses locks,
locks acquired by the implementation will be held when any use_count adjustments are performed, and will
not be held when any destruction or deallocation resulting from this is performed.
— end note ]
23.11.8.1
Atomic specialization for shared_ptr
[util.smartptr.atomic.shared]
namespace std {
template<class T> struct atomic<shared_ptr<T>> {
using value_type = shared_ptr<T>;
static constexpr bool is_always_lock_free = implementation-defined ;
bool is_lock_free() const noexcept;
void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
operator shared_ptr<T>() const noexcept;
shared_ptr<T> exchange(shared_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
constexpr atomic() noexcept = default;
atomic(shared_ptr<T> desired) noexcept;
atomic(const atomic&) = delete;
void operator=(const atomic&) = delete;
void operator=(shared_ptr<T> desired) noexcept;
§ 23.11.8.1
575
private:
shared_ptr<T> p;
// exposition only
};
}
constexpr atomic() noexcept = default;
1
Effects: Initializes p{}.
atomic(shared_ptr<T> desired) noexcept;
2
Effects: Initializes the object with the value desired. Initialization is not an atomic operation
(6.8.2).
[Note: It is possible to have an access to an atomic object A race with its construction, for
example, by communicating the address of the just-constructed object A to another thread via memory_-
order::relaxed operations on a suitable atomic pointer variable, and then immediately accessing A in
the receiving thread. This results in undefined behavior.
— end note ]
void store(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
3
Requires: The order argument shall not be memory_order::consume, memory_order::acquire, nor
memory_order::acq_rel.
4
Effects: Atomically replaces the value pointed to by this with the value of desired as if by
p.swap(desired). Memory is affected according to the value of order.
void operator=(shared_ptr<T> desired) noexcept;
5
Effects: Equivalent to store(desired).
shared_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
6
Requires: order shall not be memory_order::release nor memory_order::acq_rel.
7
Effects: Memory is affected according to the value of order.
8
Returns: Atomically returns p.
operator shared_ptr<T>() const noexcept;
9
Effects: Equivalent to: return load();
shared_ptr<T> exchange(shared_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
10
Effects: Atomically replaces p with desired as if by p.swap(desired). Memory is affected according
to the value of order. This is an atomic read-modify-write operation (6.8.2.1).
11
Returns: Atomically returns the value of p immediately before the effects.
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
12
Requires: failure shall not be memory_order::release nor memory_order::acq_rel.
13
Effects: If p is equivalent to expected, assigns desired to p and has synchronization semantics
corresponding to the value of success, otherwise assigns p to expected and has synchronization
semantics corresponding to the value of failure.
14
Returns: true if p was equivalent to expected, false otherwise.
15
Remarks: Two shared_ptr objects are equivalent if they store the same pointer value and either share
ownership, or both are empty. The weak form may fail spuriously. See 32.6.1.
16
If the operation returns true, expected is not accessed after the atomic update and the operation
is an atomic read-modify-write operation (6.8.2) on the memory pointed to by this. Otherwise, the
operation is an atomic load operation on that memory, and expected is updated with the existing value
read from the atomic object in the attempted atomic update. The use_count update corresponding to
the write to expected is part of the atomic operation. The write to expected itself is not required to
be part of the atomic operation.
§ 23.11.8.1
576
bool compare_exchange_weak(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
17
Effects: Equivalent to:
return compare_exchange_weak(expected, desired, order, fail_order);
where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced
by the value memory_order::acquire and a value of memory_order::release shall be replaced by
the value memory_order::relaxed.
bool compare_exchange_strong(shared_ptr<T>& expected, shared_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
18
Effects: Equivalent to:
return compare_exchange_strong(expected, desired, order, fail_order);
where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced
by the value memory_order::acquire and a value of memory_order::release shall be replaced by
the value memory_order::relaxed.
23.11.8.2
Atomic specialization for weak_ptr
[util.smartptr.atomic.weak]
namespace std {
template<class T> struct atomic<weak_ptr<T>> {
using value_type = weak_ptr<T>;
static constexpr bool is_always_lock_free = implementation-defined ;
bool is_lock_free() const noexcept;
void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
operator weak_ptr<T>() const noexcept;
weak_ptr<T> exchange(weak_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
bool compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
constexpr atomic() noexcept = default;
atomic(weak_ptr<T> desired) noexcept;
atomic(const atomic&) = delete;
void operator=(const atomic&) = delete;
void operator=(weak_ptr<T> desired) noexcept;
private:
weak_ptr<T> p;
// exposition only
};
}
constexpr atomic() noexcept = default;
1
Effects: Initializes p{}.
atomic(weak_ptr<T> desired) noexcept;
2
Effects: Initializes the object with the value desired. Initialization is not an atomic
operation
(6.8.2).
[Note: It is possible to have an access to an atomic object A race with its construction, for
example, by communicating the address of the just-constructed object A to another thread via memory_-
order::relaxed operations on a suitable atomic pointer variable, and then immediately accessing A in
the receiving thread. This results in undefined behavior.
— end note ]
§ 23.11.8.2
577
void store(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
3
Requires: The order argument shall not be memory_order::consume, memory_order::acquire, nor
memory_order::acq_rel.
4
Effects: Atomically replaces the value pointed to by this with the value of desired as if by
p.swap(desired). Memory is affected according to the value of order.
void operator=(weak_ptr<T> desired) noexcept;
5
Effects: Equivalent to store(desired).
weak_ptr<T> load(memory_order order = memory_order::seq_cst) const noexcept;
6
Requires: order shall not be memory_order::release nor memory_order::acq_rel.
7
Effects: Memory is affected according to the value of order.
8
Returns: Atomically returns p.
operator weak_ptr<T>() const noexcept;
9
Effects: Equivalent to: return load();
weak_ptr<T> exchange(weak_ptr<T> desired, memory_order order = memory_order::seq_cst) noexcept;
10
Effects: Atomically replaces p with desired as if by p.swap(desired). Memory is affected according
to the value of order. This is an atomic read-modify-write operation (6.8.2.1).
11
Returns: Atomically returns the value of p immediately before the effects.
bool
compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
bool
compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order success, memory_order failure) noexcept;
12
Requires: failure shall not be memory_order::release nor memory_order::acq_rel.
13
Effects: If p is equivalent to expected, assigns desired to p and has synchronization semantics
corresponding to the value of success, otherwise assigns p to expected and has synchronization
semantics corresponding to the value of failure.
14
Returns: true if p was equivalent to expected, false otherwise.
15
Remarks: Two weak_ptr objects are equivalent if they store the same pointer value and either share
ownership, or both are empty. The weak form may fail spuriously. See 32.6.1.
16
If the operation returns true, expected is not accessed after the atomic update and the operation
is an atomic read-modify-write operation (6.8.2) on the memory pointed to by this. Otherwise, the
operation is an atomic load operation on that memory, and expected is updated with the existing value
read from the atomic object in the attempted atomic update. The use_count update corresponding to
the write to expected is part of the atomic operation. The write to expected itself is not required to
be part of the atomic operation.
bool
compare_exchange_weak(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
17
Effects: Equivalent to:
return compare_exchange_weak(expected, desired, order, fail_order);
where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced
by the value memory_order::acquire and a value of memory_order::release shall be replaced by
the value memory_order::relaxed.
bool
compare_exchange_strong(weak_ptr<T>& expected, weak_ptr<T> desired,
memory_order order = memory_order::seq_cst) noexcept;
18
Effects: Equivalent to:
return compare_exchange_strong(expected, desired, order, fail_order);
§ 23.11.8.2
578
where fail_order is the same as order except that a value of memory_order::acq_rel shall be replaced
by the value memory_order::acquire and a value of memory_order::release shall be replaced by
the value memory_order::relaxed.
23.12
Memory resources
[mem.res]
23.12.1
Header <memory_resource> synopsis
[mem.res.syn]
namespace std::pmr {
// 23.12.2, class memory_resource
class memory_resource;
bool operator==(const memory_resource& a, const memory_resource& b)
noexcept;
bool operator!=(const memory_resource& a, const memory_resource& b)
noexcept;
// 23.12.3, class template polymorphic_allocator
template<class Tp> class polymorphic_allocator;
template<class T1, class T2>
bool operator==(const polymorphic_allocator<T1>& a,
const polymorphic_allocator<T2>& b) noexcept;
template<class T1, class T2>
bool operator!=(const polymorphic_allocator<T1>& a,
const polymorphic_allocator<T2>& b) noexcept;
// 23.12.4, 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;
// 23.12.5, pool resource classes
struct pool_options;
class synchronized_pool_resource;
class unsynchronized_pool_resource;
class monotonic_buffer_resource;
}
23.12.2
Class memory_resource
[mem.res.class]
1
The memory_resource class is an abstract interface to an unbounded set of classes encapsulating memory
resources.
namespace std::pmr {
class memory_resource {
static constexpr size_t max_align = alignof(max_align_t);
// exposition only
public:
virtual ~memory_resource();
[[nodiscard]] 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;
};
}
§ 23.12.2
579
23.12.2.1
memory_resource public member functions
[mem.res.public]
~memory_resource();
1
Effects: Destroys this memory_resource.
[[nodiscard]] void* allocate(size_t bytes, size_t alignment = max_align);
2
Effects: Equivalent to: return do_allocate(bytes, alignment);
void deallocate(void* p, size_t bytes, size_t alignment = max_align);
3
Effects: Equivalent to do_deallocate(p, bytes, alignment).
bool is_equal(const memory_resource& other) const noexcept;
4
Effects: Equivalent to: return do_is_equal(other);
23.12.2.2
memory_resource private virtual member functions
[mem.res.private]
virtual void* do_allocate(size_t bytes, size_t alignment) = 0;
1
Requires: alignment shall be a power of two.
2
Returns: A derived class shall implement this function to return a pointer to allocated storage (6.6.4.4.1)
with a size of at least bytes. The returned storage is aligned to the specified alignment, if such
alignment is supported (6.6.5); otherwise it is aligned to max_align.
3
Throws: A derived class implementation shall throw an appropriate exception if it is unable to allocate
memory with the requested size and alignment.
virtual void do_deallocate(void* p, size_t bytes, size_t alignment) = 0;
4
Requires: p shall have been returned from a prior call to allocate(bytes, alignment) on a memory
resource equal to *this, and the storage at p shall not yet have been deallocated.
5
Effects: A derived class shall implement this function to dispose of allocated storage.
6
Throws: Nothing.
virtual bool do_is_equal(const memory_resource& other) const noexcept = 0;
7
Returns: A derived class shall implement this function to return true if memory allocated from this
can be deallocated from other and vice-versa, otherwise false.
[Note: The most-derived type of
other might not match the type of this. For a derived class D, an implementation of this function
could immediately return false if dynamic_cast<const D*>(&other) == nullptr. — end note ]
23.12.2.3
memory_resource equality
[mem.res.eq]
bool operator==(const memory_resource& a, const memory_resource& b) noexcept;
1
Returns: &a == &b || a.is_equal(b).
bool operator!=(const memory_resource& a, const memory_resource& b) noexcept;
2
Returns: !(a == b).
23.12.3
Class template polymorphic_allocator
[mem.poly.allocator.class]
1
A specialization of class template pmr::polymorphic_allocator conforms to the Allocator requirements
(20.5.3.5). Constructed with different memory resources, different instances of the same specialization of
pmr::polymorphic_allocator can exhibit entirely different allocation behavior. This runtime polymorphism
allows objects that use polymorphic_allocator to behave as if they used different allocator types at run
time even though they use the same static allocator type.
namespace std::pmr {
template<class Tp>
class polymorphic_allocator {
memory_resource* memory_rsrc;
// exposition only
public:
using value_type = Tp;
§ 23.12.3
580
// 23.12.3.1, constructors
polymorphic_allocator() noexcept;
polymorphic_allocator(memory_resource* r);
polymorphic_allocator(const polymorphic_allocator& other) = default;
template<class U>
polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
polymorphic_allocator& operator=(const polymorphic_allocator&
rhs) = delete;
// 23.12.3.2, member functions
[[nodiscard]] Tp* allocate(size_t n);
void deallocate(Tp* p, size_t n);
template<class T, class... Args>
void construct(T* p, Args&&... args);
template<class T1, class T2, class... Args1, class... Args2>
void construct(pair<T1, T2>* p, piecewise_construct_t,
tuple<Args1...> x, tuple<Args2...> y);
template<class T1, class T2>
void construct(pair<T1, T2>* p);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, U&& x, V&& y);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, const pair<U, V>& pr);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, pair<U, V>&& pr);
template<class T>
void destroy(T* p);
polymorphic_allocator select_on_container_copy_construction()
const;
memory_resource* resource() const;
};
}
23.12.3.1
polymorphic_allocator constructors
[mem.poly.allocator.ctor]
polymorphic_allocator() noexcept;
1
Effects: Sets memory_rsrc to get_default_resource().
polymorphic_allocator(memory_resource* r);
2
Requires: r is non-null.
3
Effects: Sets memory_rsrc to r.
4
Throws: Nothing.
5
[ Note: This constructor provides an implicit conversion from memory_resource*.
— end note ]
template<class U>
polymorphic_allocator(const polymorphic_allocator<U>& other) noexcept;
6
Effects: Sets memory_rsrc to other.resource().
23.12.3.2
polymorphic_allocator member functions
[mem.poly.allocator.mem]
[[nodiscard]] Tp* allocate(size_t n);
1
Effects: Equivalent to:
return static_cast<Tp*>(memory_rsrc->allocate(n * sizeof(Tp), alignof(Tp)));
§ 23.12.3.2
581
void deallocate(Tp* p, size_t n);
2
Requires: p was allocated from a memory resource x, equal to *memory_rsrc, using x.allocate(n *
sizeof(Tp), alignof(Tp)).
3
Effects: Equivalent to memory_rsrc->deallocate(p, n * sizeof(Tp), alignof(Tp)).
4
Throws: Nothing.
template<class T, class... Args>
void construct(T* p, Args&&... args);
5
Requires: Uses-allocator construction of T with allocator resource() (see 23.10.8.2) and constructor
arguments std::forward<Args>(args)... is well-formed.
[Note: Uses-allocator construction is
always well-formed for types that do not use allocators. — end note ]
6
Effects: Construct a T object in the storage whose address is represented by p by uses-allocator
construction with allocator resource() and constructor arguments std::forward<Args>(args)
7
Throws: Nothing unless the constructor for T throws.
template<class T1, class T2, class... Args1, class... Args2>
void construct(pair<T1, T2>* p, piecewise_construct_t, tuple<Args1...> x, tuple<Args2...> y);
8
[Note: This member function and the construct member functions that follow are overloads for
piecewise construction of pairs (23.4.2).
— end note ]
9
Effects: Let xprime be a tuple constructed from x according to the appropriate rule from the following
list.
[ Note: The following description can be summarized as constructing a pair<T1, T2> object in the
storage whose address is represented by p, as if by separate uses-allocator construction with allocator
resource() (23.10.8.2) of p->first using the elements of x and p->second using the elements of y.
— end note ]
(9.1)
If uses_allocator_v<T1,memory_resource*> is false
and is_constructible_v<T1,Args1...> is true,
then xprime is x.
(9.2)
Otherwise, if uses_allocator_v<T1,memory_resource*> is true
and is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...> is true,
then xprime is tuple_cat(make_tuple(allocator_arg, resource()), std::move(x)).
(9.3)
Otherwise, if uses_allocator_v<T1,memory_resource*> is true
and is_constructible_v<T1,Args1...,memory_resource*> is true,
then xprime is tuple_cat(std::move(x), make_tuple(resource())).
(9.4)
Otherwise the program is ill formed.
Let yprime be a tuple constructed from y according to the appropriate rule from the following list:
(9.5)
If uses_allocator_v<T2,memory_resource*> is false
and is_constructible_v<T2,Args2...> is true,
then yprime is y.
(9.6)
Otherwise, if uses_allocator_v<T2,memory_resource*> is true
and is_constructible_v<T2,allocator_arg_t,memory_resource*,Args2...> is true,
then yprime is tuple_cat(make_tuple(allocator_arg, resource()), std::move(y)).
(9.7)
Otherwise, if uses_allocator_v<T2,memory_resource*> is true
and is_constructible_v<T2,Args2...,memory_resource*> is true,
then yprime is tuple_cat(std::move(y), make_tuple(resource())).
(9.8)
Otherwise the program is ill formed.
Then, using piecewise_construct, xprime, and yprime as the constructor arguments, this function
constructs a pair<T1, T2> object in the storage whose address is represented by p.
template<class T1, class T2>
void construct(pair<T1, T2>* p);
10
Effects: Equivalent to:
construct(p, piecewise_construct, tuple<>(), tuple<>());
§ 23.12.3.2
582
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, U&& x, V&& y);
11
Effects: Equivalent to:
construct(p, piecewise_construct,
forward_as_tuple(std::forward<U>(x)),
forward_as_tuple(std::forward<V>(y)));
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, const pair<U, V>& pr);
12
Effects: Equivalent to:
construct(p, piecewise_construct,
forward_as_tuple(pr.first),
forward_as_tuple(pr.second));
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, pair<U, V>&& pr);
13
Effects: Equivalent to:
construct(p, piecewise_construct,
forward_as_tuple(std::forward<U>(pr.first)),
forward_as_tuple(std::forward<V>(pr.second)));
template<class T>
void destroy(T* p);
14
Effects: As if by p->~T().
polymorphic_allocator select_on_container_copy_construction() const;
15
Returns: polymorphic_allocator().
16
[ Note: The memory resource is not propagated.
— end note ]
memory_resource* resource() const;
17
Returns: memory_rsrc.
23.12.3.3
polymorphic_allocator equality
[mem.poly.allocator.eq]
template<class T1, class T2>
bool operator==(const polymorphic_allocator<T1>& a,
const polymorphic_allocator<T2>& b) noexcept;
1
Returns: *a.resource() == *b.resource().
template<class T1, class T2>
bool operator!=(const polymorphic_allocator<T1>& a,
const polymorphic_allocator<T2>& b) noexcept;
2
Returns: !(a == b).
23.12.4
Access to program-wide memory_resource objects
[mem.res.global]
memory_resource* new_delete_resource() noexcept;
1
Returns: A pointer to a static-duration object of a type derived from memory_resource that can
serve as a resource for allocating memory using ::operator new and ::operator delete. The same
value is returned every time this function is called. For a return value p and a memory resource r,
p->is_equal(r) returns &r == p.
memory_resource* null_memory_resource() noexcept;
2
Returns: A pointer to a static-duration object of a type derived from memory_resource for which
allocate() always throws bad_alloc and for which deallocate() has no effect. The same value is
returned every time this function is called. For a return value p and a memory resource r, p->is_-
equal(r) returns &r == p.
§ 23.12.4
583
3
The 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
new_delete_resource().
memory_resource* set_default_resource(memory_resource* r) noexcept;
4
Effects: If r is non-null, sets the value of the default memory resource pointer to r, otherwise sets the
default memory resource pointer to new_delete_resource().
5
Returns: The previous value of the default memory resource pointer.
6
Remarks: Calling the set_default_resource and get_default_resource functions shall not incur a
data race. A call to the set_default_resource function shall synchronize with subsequent calls to
the set_default_resource and get_default_resource functions.
memory_resource* get_default_resource() noexcept;
7
Returns: The current value of the default memory resource pointer.
23.12.5
Pool resource classes
[mem.res.pool]
23.12.5.1
Classes synchronized_pool_resource and unsynchronized_pool_resource
[mem.res.pool.overview]
1
The synchronized_pool_resource and unsynchronized_pool_resource classes (collectively called pool
resource classes) are general-purpose memory resources having the following qualities:
(1.1)
Each resource frees its allocated memory on destruction, even if deallocate has not been called for
some of the allocated blocks.
(1.2)
A pool resource consists of a collection of pools, serving requests for different block sizes. Each individual
pool manages a collection of chunks that are in turn divided into blocks of uniform size, returned via
calls to do_allocate. Each call to do_allocate(size, alignment) is dispatched to the pool serving
the smallest blocks accommodating at least size bytes.
(1.3)
When a particular pool is exhausted, allocating a block from that pool results in the allocation of an
additional chunk of memory from the upstream allocator (supplied at construction), thus replenishing
the pool. With each successive replenishment, the chunk size obtained increases geometrically. [ Note:
By allocating memory in chunks, the pooling strategy increases the chance that consecutive allocations
will be close together in memory. — end note ]
(1.4)
Allocation requests that exceed the largest block size of any pool are fulfilled directly from the upstream
allocator.
(1.5)
A pool_options struct may be passed to the pool resource constructors to tune the largest block size
and the maximum chunk size.
2
A synchronized_pool_resource may be accessed from multiple threads without external synchronization
and may have thread-specific pools to reduce synchronization costs. An unsynchronized_pool_resource
class may not be accessed from multiple threads simultaneously and thus avoids the cost of synchronization
entirely in single-threaded applications.
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()) {}
§ 23.12.5.1
584
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;
};
}
23.12.5.2
pool_options data members
[mem.res.pool.options]
1
The members of pool_options comprise a set of constructor options for pool resources. The effect of each
option on the pool resource behavior is described below:
size_t max_blocks_per_chunk;
2
The maximum number of blocks that will be allocated at once from the upstream memory resource
(23.12.6) to replenish a pool. If the value of max_blocks_per_chunk is zero or is greater than an
implementation-defined limit, that limit is used instead. The implementation may choose to use a
smaller value than is specified in this field and may use different values for different pools.
size_t largest_required_pool_block;
3
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 largest_required_pool_block is zero or is greater than an implementation-defined limit,
that limit is used instead. The implementation may choose a pass-through threshold larger than
specified in this field.
§ 23.12.5.2
585
23.12.5.3
Pool resource constructors and destructors
[mem.res.pool.ctor]
synchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream);
1
Requires: upstream is the address of a valid memory resource.
2
Effects: Constructs a pool resource object that will obtain memory from 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 upstream, but will not own the resource to which upstream points.
[Note: The intention is that calls to upstream->allocate() will be substantially fewer than calls
to this->allocate() in most cases. — end note ] The behavior of the pooling mechanism is tuned
according to the value of the opts argument.
3
Throws: Nothing unless upstream->allocate() throws. It is unspecified if, or under what conditions,
this constructor calls upstream->allocate().
virtual ~synchronized_pool_resource();
virtual ~unsynchronized_pool_resource();
4
Effects: Calls release().
23.12.5.4
Pool resource members
[mem.res.pool.mem]
void release();
1
Effects: Calls upstream_resource()->deallocate() as necessary to release all allocated memory.
[ Note: The memory is released back to upstream_resource() even if deallocate has not been called
for some of the allocated blocks. — end note ]
memory_resource* upstream_resource() const;
2
Returns: The value of the upstream argument provided to the constructor of this object.
pool_options options() const;
3
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 implementation-defined defaults, and sizes may be rounded to unspecified granularity.
void* do_allocate(size_t bytes, size_t alignment) override;
4
Returns: A pointer to allocated storage (6.6.4.4.1) with a size of at least bytes. The size and alignment
of the allocated memory shall meet the requirements for a class derived from memory_resource (23.12).
5
Effects: If the pool selected for a block of size bytes is unable to satisfy the memory request from its
own internal data structures, it will call upstream_resource()->allocate() to obtain more memory.
If bytes is larger than that which the largest pool can handle, then memory will be allocated using
upstream_resource()->allocate().
6
Throws: Nothing unless upstream_resource()->allocate() throws.
void do_deallocate(void* p, size_t bytes, size_t alignment) override;
7
Effects: Returns the memory at p to the pool. It is unspecified if, or under what circumstances, this
operation will result in a call to upstream_resource()->deallocate().
8
Throws: Nothing.
bool synchronized_pool_resource::do_is_equal(
const memory_resource& other) const noexcept override;
9
Returns: this == dynamic_cast<const synchronized_pool_resource*>(&other).
bool unsynchronized_pool_resource::do_is_equal(
const memory_resource& other) const noexcept override;
10
Returns: this == dynamic_cast<const unsynchronized_pool_resource*>(&other).
§ 23.12.5.4
586
23.12.6
Class monotonic_buffer_resource
[mem.res.monotonic.buffer]
1
A monotonic_buffer_resource is a special-purpose memory resource intended for very fast memory alloca-
tions 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. It has the following qualities:
(1.1)
A call to deallocate has no effect, thus the amount of memory consumed increases monotonically
until the resource is destroyed.
(1.2)
The program can supply an initial buffer, which the allocator uses to satisfy memory requests.
(1.3)
When the initial buffer (if any) is exhausted, it obtains additional buffers from an upstream memory
resource supplied at construction. Each additional buffer is larger than the previous one, following a
geometric progression.
(1.4)
It is intended for access from one thread of control at a time. Specifically, calls to allocate and
deallocate do not synchronize with one another.
(1.5)
It frees the allocated memory on destruction, even if deallocate has not been called for some of the
allocated blocks.
namespace std::pmr {
class monotonic_buffer_resource : public memory_resource {
memory_resource* upstream_rsrc;
// exposition only
void* current_buffer;
// exposition only
size_t next_buffer_size;
// exposition only
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;
};
}
23.12.6.1
monotonic_buffer_resource constructor and destructor
[mem.res.monotonic.buffer.ctor]
explicit monotonic_buffer_resource(memory_resource* upstream);
monotonic_buffer_resource(size_t initial_size, memory_resource* upstream);
1
Requires: upstream shall be the address of a valid memory resource. initial_size, if specified, shall
be greater than zero.
2
Effects: Sets upstream_rsrc to upstream and current_buffer to nullptr. If initial_size is
specified, sets next_buffer_size to at least initial_size; otherwise sets next_buffer_size to an
implementation-defined size.
§ 23.12.6.1
587
monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream);
3
Requires: upstream shall be the address of a valid memory resource. buffer_size shall be no larger
than the number of bytes in buffer.
4
Effects: Sets upstream_rsrc to upstream, current_buffer to buffer, and next_buffer_size to
buffer_size (but not less than 1), then increases next_buffer_size by an implementation-defined
growth factor (which need not be integral).
~monotonic_buffer_resource();
5
Effects: Calls release().
23.12.6.2
monotonic_buffer_resource members
[mem.res.monotonic.buffer.mem]
void release();
1
Effects: Calls upstream_rsrc->deallocate() as necessary to release all allocated memory.
2
[Note: The memory is released back to upstream_rsrc even if some blocks that were allocated from
this have not been deallocated from this. — end note ]
memory_resource* upstream_resource() const;
3
Returns: The value of upstream_rsrc.
void* do_allocate(size_t bytes, size_t alignment) override;
4
Returns: A pointer to allocated storage (6.6.4.4.1) with a size of at least bytes. The size and alignment
of the allocated memory shall meet the requirements for a class derived from memory_resource (23.12).
5
Effects: If the unused space in current_buffer can fit a block with the specified bytes and alignment,
then allocate the return block from current_buffer; otherwise set current_buffer to upstream_-
rsrc->allocate(n, m), where n is not less than max(bytes, next_buffer_size) and m is not less
than alignment, and increase next_buffer_size by an implementation-defined growth factor (which
need not be integral), then allocate the return block from the newly-allocated current_buffer.
6
Throws: Nothing unless upstream_rsrc->allocate() throws.
void do_deallocate(void* p, size_t bytes, size_t alignment) override;
7
Effects: None.
8
Throws: Nothing.
9
Remarks: Memory used by this resource increases monotonically until its destruction.
bool do_is_equal(const memory_resource& other) const noexcept override;
10
Returns: this == dynamic_cast<const monotonic_buffer_resource*>(&other).
23.13
Class template scoped_allocator_adaptor
[allocator.adaptor]
23.13.1
Header <scoped_allocator> synopsis
[allocator.adaptor.syn]
namespace std {
// class template scoped allocator adaptor
template<class OuterAlloc, class... InnerAlloc>
class scoped_allocator_adaptor;
// 23.13.5, scoped allocator operators
template<class OuterA1, class OuterA2, class... InnerAllocs>
bool operator==(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
template<class OuterA1, class OuterA2, class... InnerAllocs>
bool operator!=(const scoped_allocator_adaptor<OuterA1, InnerAllocs...>& a,
const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& b) noexcept;
}
1
The class template scoped_allocator_adaptor is an allocator template that specifies the memory 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
§ 23.13.1
588
allocator becomes the 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.
[Note: The 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 ]
namespace std {
template<class OuterAlloc, class... InnerAllocs>
class scoped_allocator_adaptor : public OuterAlloc {
private:
using OuterTraits = allocator_traits<OuterAlloc>;
// exposition only
scoped_allocator_adaptor<InnerAllocs...> inner;
// exposition only
public:
using outer_allocator_type = OuterAlloc;
using inner_allocator_type = see below ;
using value_type
= typename OuterTraits::value_type;
using size_type
= typename OuterTraits::size_type;
using difference_type
= typename OuterTraits::difference_type;
using pointer
= typename OuterTraits::pointer;
using const_pointer
= typename OuterTraits::const_pointer;
using void_pointer
= typename OuterTraits::void_pointer;
using const_void_pointer
= typename OuterTraits::const_void_pointer;
using propagate_on_container_copy_assignment = see below ;
using propagate_on_container_move_assignment = see below ;
using propagate_on_container_swap
= see below ;
using is_always_equal
= see below ;
template<class Tp>
struct rebind {
using other = scoped_allocator_adaptor<
OuterTraits::template rebind_alloc<Tp>, InnerAllocs...>;
};
scoped_allocator_adaptor();
template<class OuterA2>
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<class OuterA2>
scoped_allocator_adaptor(
const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;
template<class OuterA2>
scoped_allocator_adaptor(
scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& 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;
§
23.13.1
589
[[nodiscard]] pointer allocate(size_type n);
[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint);
void deallocate(pointer p, size_type n);
size_type max_size() const;
template<class T, class... Args>
void construct(T* p, Args&&... args);
template<class T1, class T2, class... Args1, class... Args2>
void construct(pair<T1, T2>* p, piecewise_construct_t,
tuple<Args1...> x, tuple<Args2...> y);
template<class T1, class T2>
void construct(pair<T1, T2>* p);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, U&& x, V&& y);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, const pair<U, V>& x);
template<class T1, class T2, class U, class V>
void construct(pair<T1, T2>* p, pair<U, V>&& x);
template<class T>
void destroy(T* p);
scoped_allocator_adaptor select_on_container_copy_construction()
const;
};
template<class OuterAlloc, class... InnerAllocs>
scoped_allocator_adaptor(OuterAlloc, InnerAllocs...)
-> scoped_allocator_adaptor<OuterAlloc, InnerAllocs...>;
}
23.13.2
Scoped allocator adaptor member types
[allocator.adaptor.types]
using inner_allocator_type = see below ;
1
Type: scoped_allocator_adaptor<OuterAlloc> if sizeof...(InnerAllocs) is zero; otherwise,
scoped_allocator_adaptor<InnerAllocs...>.
using propagate_on_container_copy_assignment = see below ;
2
Type: true_type if allocator_traits<A>::propagate_on_container_copy_assignment::value is
true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_type.
using propagate_on_container_move_assignment = see below ;
3
Type: true_type if allocator_traits<A>::propagate_on_container_move_assignment::value is
true for any A in the set of OuterAlloc and InnerAllocs...; otherwise, false_type.
using propagate_on_container_swap = see below ;
4
Type: true_type if allocator_traits<A>::propagate_on_container_swap::value is true for any
A in the set of OuterAlloc and InnerAllocs...; otherwise, false_type.
using is_always_equal = see below ;
5
Type: true_type if allocator_traits<A>::is_always_equal::value is true for every A in the set
of OuterAlloc and InnerAllocs...; otherwise, false_type.
23.13.3
Scoped allocator adaptor constructors
[allocator.adaptor.cnstr]
scoped_allocator_adaptor();
1
Effects: Value-initializes the OuterAlloc base class and the inner allocator object.
template<class OuterA2>
scoped_allocator_adaptor(OuterA2&& outerAlloc, const InnerAllocs&... innerAllocs) noexcept;
2
Effects: Initializes the OuterAlloc base class with std::forward<OuterA2>(outerAlloc) and inner
with innerAllocs...
(hence recursively initializing each allocator within the adaptor with the
corresponding allocator from the argument list).
§ 23.13.3
590
3
Remarks: This constructor shall not participate in overload resolution unless is_constructible_-
v<OuterAlloc, OuterA2> is true.
scoped_allocator_adaptor(const scoped_allocator_adaptor& other) noexcept;
4
Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.
scoped_allocator_adaptor(scoped_allocator_adaptor&& other) noexcept;
5
Effects: Move constructs each allocator within the adaptor with the corresponding allocator from
other.
template<class OuterA2>
scoped_allocator_adaptor(
const scoped_allocator_adaptor<OuterA2, InnerAllocs...>& other) noexcept;
6
Effects: Initializes each allocator within the adaptor with the corresponding allocator from other.
7
Remarks: This constructor shall not participate in overload resolution unless is_constructible_-
v<OuterAlloc, const OuterA2&> is true.
template<class OuterA2>
scoped_allocator_adaptor(scoped_allocator_adaptor<OuterA2, InnerAllocs...>&& other) noexcept;
8
Effects: Initializes each allocator within the adaptor with the corresponding allocator rvalue from
other.
9
Remarks: This constructor shall not participate in overload resolution unless is_constructible_-
v<OuterAlloc, OuterA2> is true.
23.13.4
Scoped allocator adaptor members
[allocator.adaptor.members]
1
In the construct member functions, OUTERMOST(x) is x if x does not have an outer_allocator() member
function and OUTERMOST(x.outer_allocator()) otherwise; OUTERMOST_ALLOC_TRAITS(x) is allocator_-
traits<decltype(OUTERMOST(x))>. [ Note: OUTERMOST(x) and OUTERMOST_ALLOC_TRAITS(x) are recursive
operations. It is incumbent upon the definition of outer_allocator() to ensure that the recursion terminates.
It will terminate for all instantiations of scoped_allocator_adaptor.
— end note ]
inner_allocator_type& inner_allocator() noexcept;
const inner_allocator_type& inner_allocator() const noexcept;
2
Returns: *this if sizeof...(InnerAllocs) is zero; otherwise, inner.
outer_allocator_type& outer_allocator() noexcept;
3
Returns: static_cast<OuterAlloc&>(*this).
const outer_allocator_type& outer_allocator() const noexcept;
4
Returns: static_cast<const OuterAlloc&>(*this).
[[nodiscard]] pointer allocate(size_type n);
5
Returns: allocator_traits<OuterAlloc>::allocate(outer_allocator(), n).
[[nodiscard]] pointer allocate(size_type n, const_void_pointer hint);
6
Returns: allocator_traits<OuterAlloc>::allocate(outer_allocator(), n, hint).
void deallocate(pointer p, size_type n) noexcept;
7
Effects: As if by: allocator_traits<OuterAlloc>::deallocate(outer_allocator(), p, n);
size_type max_size() const;
8
Returns: allocator_traits<OuterAlloc>::max_size(outer_allocator()).
template<class T, class... Args>
void construct(T* p, Args&&... args);
9
Effects:
(9.1)
If uses_allocator_v<T, inner_allocator_type> is false and is_constructible_v<T,
Args...> is true, calls:
§ 23.13.4
591

 

 

 

 

 

 

 

Content      ..     18      19      20      21     ..