Re: Self-assignment check in move assignment operator? (for unique_ptr)
Martin B. wrote:
What's the current status of allowing/disallowing
self-move-assignment in C++0x?
(I hope "move assignment operator" and "self move assignment" are
the correct terms?)
In 2009, Dave Abrahams posted [1] an example of a unique_ptr:
[...]
unique_ptr& operator=(unique_ptr&& p) {
delete ptr_; ptr_ = p.ptr_;
p.ptr_ = 0;
return *this;
}
[...]
This simple example would obviously fail for self-move-assignment.
In the article [1], there follows a short discussion and Howard
Hinnant posts: (September 18, 2009 at 6:50 am)
[... Is a=std::move(a); legal? ...]
It is advisable to allow self-move assignment in only very limited
circumstances. Namely when "a" has already been moved from (is
resourceless). It is my hope that the move assignment operator need
not go to the trouble or expense of checking for self move
assignment:
http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#1204
I.e. A::operator(A&& a) should be able to assume that "a" really
does refer to a temporary.
(Note that his quoted link seems broken.)
That was a preview, try this instead:
http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#1204
Looking at the current std draft [2], the definition of
std::unique_ptr is as follows:
--std--
20.9.10.2.3 unique_ptr assignment
2 Effects: Transfers ownership from u to *this as if by calling
reset(u.release()) followed by [...]
20.9.10.2.5 unique_ptr modifiers
pointer release();
1 Postcondition: get() == nullptr.
2 Returns: The value get() had at the start of the call to
release.
void reset(pointer p = pointer());
4 Requires: The expression get_deleter()(get()) shall be well
formed, shall have well-defined behavior, [...]
5 Effects: assigns p to the stored pointer, and then if the old
value of the stored pointer, old_p, was not equal to
nullptr, calls get_deleter()(old_p).
( Note: the order of these operations is significant
because the call to get_deleter() may destroy *this.
-end note )
6 Postconditions: get() == p.
--std--
This seems to allow self move, as release() zero's out the our
pointer and reset() then re-sets it - correct?
The current Visual C++ 2010 implementation is:
_Myt& operator=(_Myt&& _Right)
{ // assign by moving _Right
if (this != &_Right)
{ // different, do the move
reset(_Right.release());
[...]
They explicitly check for self-assignment.
I belive that implementation is older than the resolution to issue 1204. Now it
is possibly overly conservative.
So ...
* Should a move assignment operator= explicitly *check* for self
assignment? * Should self-move-assignment be OK in general? (as it
appears to
be for std::unique_ptr) -- That is, should move-assignment always
work for self-assignment? (as is recommended for the copy
assignment operator)
The resolution to issue 1204 says that "unlike explicitly stated otherwise" an
rvalue can be treated as a temporary. To me, this means that anyone doing
a = std::move(a);
is responible for what happens. If a is of a class type you have defined
yourself, this could be fine. If a is some kind of standard container, it
probably will not.
The std::unique_pointer might be a case were the semantics are "explicitly
stated otherwise".
Bo Persson
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]