Title
unique_ptr::reset effects incorrect, too permissive
Status
cd1
Section
[unique.ptr.single.modifiers]
Submitter
Peter Dimov

Created on 2008-03-13.00:00:00 last changed 172 months ago

Messages

Date: 2010-10-21.18:28:33

Proposed resolution:

Change [unique.ptr.single.modifiers]:

void reset(T* p = 0);

-4- Effects: If p == get() == 0 there are no effects. Otherwise get_deleter()(get()).

Change [unique.ptr.runtime.modifiers]:

void reset(T* p = 0);

...

-2- Effects: If p == get() == 0 there are no effects. Otherwise get_deleter()(get()).

Date: 2008-03-13.00:00:00

void unique_ptr::reset(T* p = 0) is currently specified as:

Effects: If p == get() there are no effects. Otherwise get_deleter()(get()).

There are two problems with this. One, if get() == 0 and p != 0, the deleter is called with a NULL pointer, and this is probably not what's intended (the destructor avoids calling the deleter with 0.)

Two, the special check for get() == p is generally not needed and such a situation usually indicates an error in the client code, which is being masked. As a data point, boost::shared_ptr was changed to assert on such self-resets in 2001 and there were no complaints.

One might think that self-resets are necessary for operator= to work; it's specified to perform

reset( u.release() );

and the self-assignment

p = move(p);

might appear to result in a self-reset. But it doesn't; the release() is performed first, zeroing the stored pointer. In other words, p.reset( q.release() ) works even when p and q are the same unique_ptr, and there is no need to special-case p.reset( q.get() ) to work in a similar scenario, as it definitely doesn't when p and q are separate.

History
Date User Action Args
2010-10-21 18:28:33adminsetmessages: + msg3841
2008-03-13 00:00:00admincreate