I have detected two distinct problems (b and c) with an implementation derived from the current wording (a) concerning auto_ptr. I have an unrelated remark in addition (d). -a------------------------------ My comments below will refer to the following extract of the working paper of the draft (in [lib.auto.ptr], p 20-26 of the "DRAFT: 20 September 1996"): -------- 1: template auto_ptr& operator=(const auto_ptr& a) throw(); 2: 3: Requires: Y is type X or a class derived from X for which delete 4: (Y*) is defined and accessible. 5: Effects: If *this owns *get() and *this != &a then delete get(). 6: Calls a.release(). 7: Returns: *this. 8: Postconditions: *this holds the pointer returned from a.release(). 9: *this owns *get() if and only if a owns *a. -b------------------------------ Problem 1: an auto_ptr target of a self-assignment dangles. This is because of the unconditional call to a.release() on line 6. -c------------------------------ Problem 2: there is a leak in some situations such as: p = q; p = q; After the first assignment, both p and q point to the same resource, but p owns it. This ownership -and thus any ownership of the resource- is lost during the second assignment. Similar cases are met every time when, in an assignment "p = q;", p and q both point to the same resource, but p owns it. -------- Commentary: The ambiguity about the behaviour shows in the following slip: 5: Effects: If *this owns *get() and *this != &a then delete get(). ^ Should one read: "this != &a" or "this->get() != a.get()"? I argue that this behaviour is not acceptable, for several reasons: - This behavior loses compared to plain pointers (loss of safety!). - It results -in my example above- from the fact that the assignment modifies its const argument through the use of mutable, in a way that is not anymore semantically free for the user. I claim that this is an abuse of "mutable". - The current behavior is surprising for users, even if it results from a simple specification. - The main area of use for auto_ptrs is likely to be the writing of simple exception safe code. What is expected of "exception safe" code is mostly code that doesn't leak in presence of exceptions. It is therefore especially critical to prevent this kind of problems. -------- Proposal: Effects: If this == &a, skip. Otherwise, consider two cases: *this and a hold pointers to different resources, or to the same resource. In the first case, if *this owns *get, delete get(); then transfer the ownership and the pointer. In the second case, take care that the ownership is not lost. In both cases, insure that a doesn't own the pointer. Postconditions: *this holds the pointer returned from a.get(). *this owns *get() if and only if either of *this or a owned it previously. Example of implementation: template auto_ptr& operator=(const auto_ptr& r) throw() { if ((void*)&r != (void*)this) { // I didn't understand Greg's test if (px != r.px) if (owner) delete px; owner = r.owner; px = r.px; } else owner |= r.owner; // don't transfer non-ownership to owner r.owner = 0; } return *this; } -d------------------------------ Remark: on line 3, shouldn't one mention the case of const conversion? -------- auto_ptr p; auto_ptr q; p = q; -------- 3: Requires: Y is type X or a class derived from X for which delete ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In this example, Y is neither X, nor a class derived from X. Or should one say: Requires: Y is reference-compatible with X and delete(Y*) is defined and accessible (see [dcl.init.ref]).