construct
/destroy
in allocate_shared
Section: 20.3.2.2.7 [util.smartptr.shared.create] Status: Tentatively Ready Submitter: Billy O'Neal III Opened: 2019-06-11 Last modified: 2024-10-02
Priority: 3
View other active issues in [util.smartptr.shared.create].
View all other issues in [util.smartptr.shared.create].
View all issues with Tentatively Ready status.
Discussion:
The new allocate_shared
wording says we need to rebind the allocator back to T
's
type before we can call construct
or destroy
, but this is suboptimal (might make
extra unnecessary allocator copies), and is inconsistent with the containers' behavior, which call
allocator construct
on whatever T
they want. (For example,
std::list<T, alloc<T>>
rebinds to alloc<_ListNode<T>>
,
but calls construct(T*)
without rebinding back)
[2019-07 Issue Prioritization]
Priority to 3 after discussion on the reflector.
Previous resolution [SUPERSEDED]:
This wording is relative to N4810.
Modify 20.3.2.2.7 [util.smartptr.shared.create] as indicated:
[Drafting note: The edits to change
pv
topu
were suggested by Jonathan Wakely (thanks!). This wording also has theremove_cv_t
fixes specified by LWG 3210 — if that change is rejected some of those have to be stripped here.]template<class T, ...> shared_ptr<T> make_shared(args); template<class T, class A, ...> shared_ptr<T> allocate_shared(const A& a, args); template<class T, ...> shared_ptr<T> make_shared_default_init(args); template<class T, class A, ...> shared_ptr<T> allocate_shared_default_init(const A& a, args);-2- Requires: […]
[…] -7- Remarks:
(7.1) — […]
[…]
(7.5) — When a (sub)object of a non-array type
U
is specified to have an initial value ofv
, orU(l...)
, wherel...
is a list of constructor arguments,allocate_shared
shall initialize this (sub)object via the expression
(7.5.1) —
allocator_traits<A2>::construct(a2, p
orvu, v)(7.5.2) —
allocator_traits<A2>::construct(a2, p
vu, l...)respectively, where
p
is a pointer of typevuremove_cv_t<U>*
pointsing to storage suitable to hold an object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>
(7.6) — […]
(7.7) — When a (sub)object of non-array type
U
is specified to have a default initial value,allocate_shared
shallinitializes this (sub)object via the expressionallocator_traits<A2>::construct(a2, p
, wherevu)p
is a pointer of typevuremove_cv_t<U>*
pointsing to storage suitable to hold an object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>
[…]
(7.12) — When a (sub)object of non-array type
U
that was initialized byallocate_shared
is to be destroyed, it is destroyed via the expressionallocator_traits<A2>::destroy(a2, p
wherevu)p
is a pointer of typevuremove_cv_t<U>*
pointsing to that object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>
[2024-08-23; Jonathan provides updated wording]
make_shared_default_init
and allocate_shared_default_init
were renamed
by P1973R1 so this needs a rebase.
The edit to (7.11) is just for consistency, so that pv
is always void*
and pu
is remove_cv_t<U>*
.
Accepting this proposed resolution would also resolve issue 3210.
[2024-10-02; Reflector poll]
Set status to Tentatively Ready after six votes in favour during reflector poll.
Proposed resolution:
This wording is relative to N4988.
Modify 20.3.2.2.7 [util.smartptr.shared.create] as indicated:
template<class T, ...> shared_ptr<T> make_shared(args); template<class T, class A, ...> shared_ptr<T> allocate_shared(const A& a, args); template<class T, ...> shared_ptr<T> make_shared_for_overwrite(args); template<class T, class A, ...> shared_ptr<T> allocate_shared_for_overwrite(const A& a, args);-2- Preconditions: […]
[…] -7- Remarks:
(7.1) — […]
[…]
(7.5) — When a (sub)object of a non-array type
U
is specified to have an initial value ofv
, orU(l...)
, wherel...
is a list of constructor arguments,allocate_shared
shall initialize this (sub)object via the expression
(7.5.1) —
allocator_traits<A2>::construct(a2, p
orvu, v)(7.5.2) —
allocator_traits<A2>::construct(a2, p
vu, l...)respectively, where
p
is a pointer of typevuremove_cv_t<U>*
pointsing to storage suitable to hold an object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>
(7.6) — […]
(7.7) — When a (sub)object of non-array type
U
is specified to have a default initial value,allocate_shared
shallinitializes this (sub)object via the expressionallocator_traits<A2>::construct(a2, p
, wherevu)p
is a pointer of typevuremove_cv_t<U>*
pointsing to storage suitable to hold an object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>
[…]
[Drafting note: Issue 4024 will add
make_shared_for_overwrite
andallocate_shared_for_overwrite
to (7.11) but that doesn't conflict with this next edit.](7.11) — When a (sub)object of non-array type
U
that was initialized bymake_shared
is to be destroyed, it is destroyed via the expressionp
wherevu->~U()p
points to that object of typevuU
.(7.12) — When a (sub)object of non-array type
U
that was initialized byallocate_shared
is to be destroyed, it is destroyed via the expressionallocator_traits<A2>::destroy(a2, p
wherevu)p
is a pointer of typevuremove_cv_t<U>*
pointsing to that object of typeremove_cv_t<U>
anda2
of typeA2
is a potentially rebound copy of the allocatora
passed toallocate_shared
such that its.value_type
isremove_cv_t<U>