This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

### 3216. Rebinding the allocator before calling `construct`/`destroy` in `allocate_shared`

Section: 20.11.3.7 [util.smartptr.shared.create] Status: New Submitter: Billy O'Neal III Opened: 2019-06-11 Last modified: 2020-09-06

Priority: 3

View other active issues in [util.smartptr.shared.create].

View all other issues in [util.smartptr.shared.create].

View all issues with New 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)

It seems like we should be consistent with the containers and not require a rebind here. PR would look something like this, relative to N4810; I'm still not super happy with this wording because it looks like it might be saying a copy of the allocator must be made we would like to avoid…

[2019-07 Issue Prioritization]

Priority to 3 after discussion on the reflector.

Proposed resolution:

This wording is relative to N4810.

1. Modify 20.11.3.7 [util.smartptr.shared.create] as indicated:

   > [Drafting note: The edits to change `pv` to `pu` were suggested by Jonathan Wakely (thanks!). This wording also has the `remove_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:

   > > 1. (7.1) — […]

   > > 2. […]

   > > 3. (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

   > >    1. (7.5.1) — `allocator_traits<A2>::construct(a2, pvu, v)` or

   > >    2. (7.5.2) — `allocator_traits<A2>::construct(a2, pvu, l...)`

   > >    respectively, where `pvu` is a pointer of type `remove_cv_t<U>*` points ing to storage suitable to hold an object of type `remove_cv_t<U>` and `a2` of type `A2` is a potentially rebound copy of the allocator `a` passed to `allocate_shared` such that its `value_type` is `remove_cv_t<U>`.

   > > 4. (7.6) — […]

   > > 5. (7.7) — When a (sub)object of non-array type `U` is specified to have a default initial value, `allocate_shared` shall initializes this (sub)object via the expression `allocator_traits<A2>::construct(a2, pvu)`, where `pvu` is a pointer of type `remove_cv_t<U>*` points ing to storage suitable to hold an object of type `remove_cv_t<U>` and `a2` of type `A2` is a potentially rebound copy of the allocator `a` passed to `allocate_shared` such that its `value_type` is `remove_cv_t<U>`.

   > > 6. […]

   > > 7. (7.12) — When a (sub)object of non-array type `U` that was initialized by `allocate_shared` is to be destroyed, it is destroyed via the expression `allocator_traits<A2>::destroy(a2, pvu)` where `pvu` is a pointer of type `remove_cv_t<U>*` points ing to that object of type `remove_cv_t<U>` and `a2` of type `A2` is a potentially rebound copy of the allocator `a` passed to `allocate_shared` such that its `value_type` is `remove_cv_t<U>`.