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

### 758. `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 write `px.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 of `d((T*)0)` when `p` is `nullptr`.

> The ability to be able to pass `0/NULL` to a function that takes a `shared_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 the pointer object `p` and the deleter `d`. The second constructor shall use a copy of `a` 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.