shared_ptr
and nullptr
Section: 20.3.2.2 [util.smartptr.shared] Status: C++11 Submitter: Joe Gottman Opened: 2007-10-31 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [util.smartptr.shared].
View all issues with C++11 status.
Discussion:
Consider the following program:
int main() { shared_ptr<int> p(nullptr); return 0; }
This program will fail to compile because shared_ptr
uses the following
template constructor to construct itself from pointers:
template <class Y> shared_ptr(Y *);
According
to N2431,
the conversion from nullptr_t
to Y *
is not
deducible, so the above constructor will not be found. There are similar problems with the
constructors that take a pointer and a deleter
or a
pointer, a deleter
and an allocator, as well as the
corresponding forms of reset()
. Note that N2435
will solve this problem for constructing from just nullptr
, but not for constructors that use
deleters
or allocators or for reset()
.
In the case of the functions that take deleters, there is the additional
question of what argument should be passed to the deleter when it is
eventually called. There are two reasonable possibilities: nullptr
or
static_cast<T *>(0)
, where T
is the template argument of the
shared_ptr
. It is not immediately clear which of these is better. If
D::operator()
is a template function similar to shared_ptr
's
constructor, then d(static_cast<T*>(0))
will compile and d(nullptr)
will not. On the other hand, if D::operator()()
takes a parameter that
is a pointer to some type other that T
(for instance U*
where U
derives
from T
) then d(nullptr)
will compile and d(static_cast<T *>(0))
may not.
[ Bellevue: ]
The general idea is right, we need to be able to pass a nullptr to a shared_ptr, but there are a few borderline editorial issues here. (For example, the single-argument nullptr_t constructor in the class synopsis isn't marked explicit, but it is marked explicit in the proposed wording for 20.6.6.2.1. There is a missing empty parenthesis in the form that takes a nullptr_t, a deleter, and an allocator.)
More seriously: this issue says that a shared_ptr constructed from a nullptr is empty. Since "empty" is undefined, it's hard to know whether that's right. This issue is pending on handling that term better.
Peter suggests definition of empty should be "does not own anything"
Is there an editorial issue that post-conditions should refer to get() = nullptr, rather than get() = 0?
No strong feeling towards accept or NAD, but prefer to make a decision than leave it open.
Seems there are no technical merits between NAD and Ready, comes down to "Do we intentially want to allow/disallow null pointers with these functions". Staw Poll - support null pointers 5 - No null pointers 0
Move to Ready, modulo editorial comments
[ post Bellevue Peter adds: ]
The following wording changes are less intrusive:
In 20.3.2.2.2 [util.smartptr.shared.const], add:
shared_ptr(nullptr_t);after:
shared_ptr();(Absence of explicit intentional.)
px.reset( nullptr )
seems a somewhat contrived way to writepx.reset()
, so I'm not convinced of its utility.It's similarly not clear to me whether the deleter constructors need to be extended to take
nullptr
, but if they need to:Add
template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);after
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);Note that this changes the semantics of the new constructors such that they consistently call
d(p)
instead ofd((T*)0)
whenp
isnullptr
.The ability to be able to pass
0/NULL
to a function that takes ashared_ptr
has repeatedly been requested by users, but the other additions that the proposed resolution makes are not supported by real world demand or motivating examples.It might be useful to split the obvious and non-controversial
nullptr_t
constructor into a separate issue. Waiting for "empty" to be clarified is unnecessary; this is effectively an alias for the default constructor.
[ Sophia Antipolis: ]
We want to remove the reset functions from the proposed resolution.
The remaining proposed resolution text (addressing the constructors) are wanted.
Disposition: move to review. The review should check the wording in the then-current working draft.
Proposed resolution:
In 20.3.2.2 [util.smartptr.shared] p4, add to the definition/synopsis
of shared_ptr
:
template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
after
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);
In 20.3.2.2.2 [util.smartptr.shared.const] add:
template<class D> shared_ptr(nullptr_t p, D d); template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
after
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);
(reusing the following paragraphs 20.3.2.2.2 [util.smartptr.shared.const]/9-13 that speak of p.)
In 20.3.2.2.2 [util.smartptr.shared.const]/10, change
Effects: Constructs a
shared_ptr
object that owns thepointerobjectp
and the deleterd
. The second constructor shall use a copy ofa
to allocate memory for internal use.
Rationale:
[ San Francisco: ]
"pointer" is changed to "object" to handle the fact that
nullptr_t
isn't a pointer.