construct/destroy in allocate_sharedSection: 20.3.2.2.7 [util.smartptr.shared.create] Status: WP Submitter: Billy O'Neal III Opened: 2019-06-11 Last modified: 2024-11-28
Priority: 3
View all other issues in [util.smartptr.shared.create].
View all issues with WP 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
pvtopuwere suggested by Jonathan Wakely (thanks!). This wording also has theremove_cv_tfixes 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
Uis specified to have an initial value ofv, orU(l...), wherel...is a list of constructor arguments,allocate_sharedshall initialize this (sub)object via the expression
(7.5.1) —
allocator_traits<A2>::construct(a2, porvu, v)(7.5.2) —
allocator_traits<A2>::construct(a2, pvu, l...)respectively, where
pis a pointer of typevuremove_cv_t<U>*pointsing to storage suitable to hold an object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_cv_t<U>(7.6) — […]
(7.7) — When a (sub)object of non-array type
Uis specified to have a default initial value,allocate_sharedshallinitializes this (sub)object via the expressionallocator_traits<A2>::construct(a2, p, wherevu)pis a pointer of typevuremove_cv_t<U>*pointsing to storage suitable to hold an object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_cv_t<U>[…]
(7.12) — When a (sub)object of non-array type
Uthat was initialized byallocate_sharedis to be destroyed, it is destroyed via the expressionallocator_traits<A2>::destroy(a2, pwherevu)pis a pointer of typevuremove_cv_t<U>*pointsing to that object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_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.
[Wrocław 2024-11-23; Status changed: Voting → WP.]
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
Uis specified to have an initial value ofv, orU(l...), wherel...is a list of constructor arguments,allocate_sharedshall initialize this (sub)object via the expression
(7.5.1) —
allocator_traits<A2>::construct(a2, porvu, v)(7.5.2) —
allocator_traits<A2>::construct(a2, pvu, l...)respectively, where
pis a pointer of typevuremove_cv_t<U>*pointsing to storage suitable to hold an object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_cv_t<U>(7.6) — […]
(7.7) — When a (sub)object of non-array type
Uis specified to have a default initial value,allocate_sharedshallinitializes this (sub)object via the expressionallocator_traits<A2>::construct(a2, p, wherevu)pis a pointer of typevuremove_cv_t<U>*pointsing to storage suitable to hold an object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_cv_t<U>[…]
[Drafting note: Issue 4024 will add
make_shared_for_overwriteandallocate_shared_for_overwriteto (7.11) but that doesn't conflict with this next edit.](7.11) — When a (sub)object of non-array type
Uthat was initialized bymake_sharedis to be destroyed, it is destroyed via the expressionpwherevu->~U()ppoints to that object of typevuU.(7.12) — When a (sub)object of non-array type
Uthat was initialized byallocate_sharedis to be destroyed, it is destroyed via the expressionallocator_traits<A2>::destroy(a2, pwherevu)pis a pointer of typevuremove_cv_t<U>*pointsing to that object of typeremove_cv_t<U>anda2of typeA2is a potentially rebound copy of the allocatorapassed toallocate_sharedsuch that its.value_typeisremove_cv_t<U>