Issue 998: Smart pointer referencing its owner (original) (raw)
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.
998. Smart pointer referencing its owner
Section: 20.3.1.3.6 [unique.ptr.single.modifiers] Status: C++11 Submitter: Pavel Minaev Opened: 2009-02-26 Last modified: 2016-01-28
Priority: Not Prioritized
View all other issues in [unique.ptr.single.modifiers].
View all issues with C++11 status.
Discussion:
Consider the following (simplified) implementation of std::auto_ptr<T>::reset():
void reset(T* newptr = 0) { if (this->ptr && this->ptr != newptr) { delete this->ptr; } this->ptr = newptr; }
Now consider the following code which uses the above implementation:
struct foo { std::auto_ptr ap; foo() : ap(this) {} void reset() { ap.reset(); } }; int main() { (new foo)->reset(); }
With the above implementation of auto_ptr, this results in U.B. at the point of auto_ptr::reset(). If this isn't obvious yet, let me explain how this goes step by step:
foo::reset()enteredauto_ptr::reset()enteredauto_ptr::reset()tries to deletefoofoo::~foo()entered, tries to destruct its membersauto_ptr::~auto_ptr()executed -auto_ptris no longer a valid object!foo::~foo()leftauto_ptr::reset()sets its "ptr" field to 0 <- U.B.!auto_ptris not a valid object here already!
[ Thanks to Peter Dimov who recognized the connection to uniqueptr and brought this to the attention of the LWG, and helped with the solution. ]
[ Howard adds: ]
To fix this behavior
resetmust be specified such that deleting the pointer is the last action to be taken withinreset.
[ Alisdair adds: ]
The example providing the rationale for LWG 998(i) is poor, as it relies on broken semantics of having two object believing they are unique owners of a single resource. It should not be surprising that UB results from such code, and I feel no need to go out of our way to support such behaviour.
If an example is presented that does not imply multiple ownership of a unique resource, I would be much more ready to accept the proposed resolution.
[ Batavia (2009-05): ]
Howard summarizes:
This issue has to do with circular ownership, and affects
auto_ptr, too (but we don't really care about that). It is intended to spell out the order in which operations must be performed so as to avoid the possibility of undefined behavior in the self-referential case.Howard points to message c++std-lib-23175 for another example, requested by Alisdair.
We agree with the issue and with the proposed resolution. Move to Tentatively Ready.
Proposed resolution:
Change 20.3.1.3.6 [unique.ptr.single.modifiers], p5 (Effects clause for reset), and p6:
-5- Effects:
IfAssignsget() == nullptrthere are no effects. Otherwiseget_deleter()(get()).pto the storedpointer, and then if the old value of thepointeris not equal tonullptr, callsget_deleter()(the old value of thepointer). [Note: The order of these operations is significant because the call toget_deleter()may destroy*this. _-- end note_]-6- Postconditions:
get() == p.[Note: The postcondition does not hold if the call toget_deleter()destroys*thissincethis->get()is no longer a valid expression. _-- end note_]