unique_ptr<T&, D>
Section: 20.3.1.3.1 [unique.ptr.single.general] Status: New Submitter: Jonathan Wakely Opened: 2024-08-30 Last modified: 2024-08-31
Priority: Not Prioritized
View all other issues in [unique.ptr.single.general].
View all issues with New 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.
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
D
isdefault_delete
. A client-supplied template argumentD
shall be a function object type (22.10 [function.objects]), lvalue reference to function, or lvalue reference to function object type for which, given a valued
of typeD
and a valueptr
of 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
D
is not a reference type,D
shall meet the Cpp17Destructible requirements (Table 35).-3- If the qualified-id
remove_reference_t<D>::pointer
is valid and denotes a type (13.10.3 [temp.deduct]), thenunique_ptr<T, D>::pointer
shall be a synonym forremove_reference_t<D>::pointer
. Otherwiseunique_ptr<T, D>::pointer
shall be a synonym forelement_type*
. The typeunique_ptr<T, D>::pointer
shall meet the Cpp17NullablePointer requirements (Table 36).-4- [Example 1: Given an allocator type
X
(16.4.4.6.1 [allocator.requirements.general]) and lettingA
be a synonym forallocator_traits<X>
, the typesA::pointer
,A::const_pointer
,A::void_pointer
, andA::const_void_pointer
may be used asunique_ptr<T, D>::pointer
. — end example]