711. Contradiction in empty shared_ptr

Section: 23.11.3.5 [util.smartptr.shared.obs] Status: C++11 Submitter: Peter Dimov Opened: 2007-08-24 Last modified: 2016-02-10

Priority: Not Prioritized

View all other issues in [util.smartptr.shared.obs].

View all issues with C++11 status.

Discussion:

A discussion on comp.std.c++ has identified a contradiction in the shared_ptr specification. The note:

[ Note: this constructor allows creation of an empty shared_ptr instance with a non-NULL stored pointer. -end note ]

after the aliasing constructor

template<class Y> shared_ptr(shared_ptr<Y> const& r, T *p);

reflects the intent of N2351 to, well, allow the creation of an empty shared_ptr with a non-NULL stored pointer.

This is contradicted by the second sentence in the Returns clause of 23.11.3.5 [util.smartptr.shared.obs]:

T* get() const;

Returns: the stored pointer. Returns a null pointer if *this is empty.

[ Bellevue: ]

Adopt option 1 and move to review, not ready.

There was a lot of confusion about what an empty shared_ptr is (the term isn't defined anywhere), and whether we have a good mental model for how one behaves. We think it might be possible to deduce what the definition should be, but the words just aren't there. We need to open an issue on the use of this undefined term. (The resolution of that issue might affect the resolution of issue 711.)

The LWG is getting more uncomfortable with the aliasing proposal (N2351) now that we realize some of its implications, and we need to keep an eye on it, but there isn't support for removing this feature at this time.

[ Sophia Antipolis: ]

We heard from Peter Dimov, who explained his reason for preferring solution 1.

Because it doesn't seem to add anything. It simply makes the behavior for p = 0 undefined. For programmers who don't create empty pointers with p = 0, there is no difference. Those who do insist on creating them presumably have a good reason, and it costs nothing for us to define the behavior in this case.

The aliasing constructor is sharp enough as it is, so "protecting" users doesn't make much sense in this particular case.

> Do you have a use case for r being empty and r being non-null?

I have received a few requests for it from "performance-conscious" people (you should be familiar with this mindset) who don't like the overhead of allocating and maintaining a control block when a null deleter is used to approximate a raw pointer. It is obviously an "at your own risk", low-level feature; essentially a raw pointer behind a shared_ptr facade.

We could not agree upon a resolution to the issue; some of us thought that Peter's description above is supporting an undesirable behavior.

[ 2009-07 Frankfurt: ]

We favor option 1, move to Ready.

[ Howard: Option 2 commented out for clarity, and can be brought back. ]

Proposed resolution:

In keeping the N2351 spirit and obviously my preference, change 23.11.3.5 [util.smartptr.shared.obs]:

T* get() const;

Returns: the stored pointer. Returns a null pointer if *this is empty.