This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of WP status.
unique_ptr<T&, D>Section: 20.3.1.3.1 [unique.ptr.single.general] Status: WP Submitter: Jonathan Wakely Opened: 2024-08-30 Last modified: 2024-11-28
Priority: Not Prioritized
View all other issues in [unique.ptr.single.general].
View all issues with WP status.
Discussion:
It seems that we currently allow nonsensical specializations of unique_ptr
such as unique_ptr<int&, D>
and unique_ptr<void()const, D>
(a custom deleter that defines D::pointer is needed, because otherwise
the pointer type would default to invalid types like
int&* or void(*)()const).
There seems to be no reason to support these "unique pointer to reference"
and "unique pointer to abominable function type" specializations,
or any specialization for a type that you couldn't form a raw pointer to.
Prior to C++17, the major library implementations rejected such specializations
as a side effect of the constraints for the
unique_ptr(auto_ptr<U>&&) constructor
being defined in terms of is_convertible<U*, T*>.
This meant that overload resolution for any constructor of unique_ptr
would attempt to form the type T* and fail if that was invalid.
With the removal of auto_ptr in C++17, that constructor was removed
and now unique_ptr<int&, D> can be instantiated
(assuming any zombie definition of auto_ptr is not enabled by the library).
This wasn't intentional, but just an accident caused by not explicitly
forbidding such types.
Discussion on the LWG reflector led to near-unanimous support for explicitly disallowing these specializations for non-pointable types.
[2024-11-13; Reflector poll]
Set status to Tentatively Ready after eight 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.1.3.1 [unique.ptr.single.general] as indicated:
-?- A program that instantiates the definition of
unique_ptr<T, D>is ill-formed ifT*is an invalid type.
[Note: This prevents the intantiation of specializations such asunique_ptr<T&, D>andunique_ptr<int() const, D>. — end note]-1- The default type for the template parameter
Disdefault_delete. A client-supplied template argumentDshall be a function object type (22.10 [function.objects]), lvalue reference to function, or lvalue reference to function object type for which, given a valuedof typeDand a valueptrof typeunique_ptr<T, D>::pointer, the expressiond(ptr)is valid and has the effect of disposing of the pointer as appropriate for that deleter.-2- If the deleter’s type
Dis not a reference type,Dshall meet the Cpp17Destructible requirements (Table 35).-3- If the qualified-id
remove_reference_t<D>::pointeris valid and denotes a type (13.10.3 [temp.deduct]), thenunique_ptr<T, D>::pointershall be a synonym forremove_reference_t<D>::pointer. Otherwiseunique_ptr<T, D>::pointershall be a synonym forelement_type*. The typeunique_ptr<T, D>::pointershall meet the Cpp17NullablePointer requirements (Table 36).-4- [Example 1: Given an allocator type
X(16.4.4.6.1 [allocator.requirements.general]) and lettingAbe a synonym forallocator_traits<X>, the typesA::pointer,A::const_pointer,A::void_pointer, andA::const_void_pointermay be used asunique_ptr<T, D>::pointer. — end example]