shared_ptr(nullptr_t, Deleter)
is overconstrained, breaking some sensible deletersSection: 20.3.2.2.2 [util.smartptr.shared.const] Status: New Submitter: Louis Dionne Opened: 2024-06-11 Last modified: 2024-06-11
Priority: Not Prioritized
View other active issues in [util.smartptr.shared.const].
View all other issues in [util.smartptr.shared.const].
View all issues with New status.
Discussion:
The following code doesn't compile on conforming implementations:
#include <memory>
void f() {
std::shared_ptr<int>(new int, [](auto pointer) { delete pointer; });
}
(Godbolt)
This is caused by the constraint on shared_ptr(nullptr_t p, D d);
being that d(p)
is valid (20.3.2.2.2 [util.smartptr.shared.const] p9),
which leads to a hard error inside the lambda since it is called with a
nullptr_t
. This seems unintended.
See LLVM issue 93071 comment for additional context.
Proposed resolution:
This wording is relative to N4981.
shared_ptr(nullptr_t p, D d);
checks whether
d(static_cast<T*>(nullptr))
is well-formed. This requires expressing the the constraints for
the Y*
constructors and the nullptr_t
constructors separately,
which is mostly editorial:
template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);-9- Constraints:
is_move_constructible_v<D>
istrue
, andd(p)
is a well-formed expression.For the first two overloads:
- (9.1) If
T
is an array type, then eitherT
isU[N]
andY(*)[N]
is convertible toT*
, orT
isU[]
andY(*)[]
is convertible toT*
.- (9.2) If
T
is not an array type, thenY*
is convertible toT*
.template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
-?- Constraints:
is_move_constructible_v<D>
istrue
, andd(static_cast<T*>(p))
is a well-formed expression.