What does the C++11 standard say about self move assignment in relation to the standard library? To be more concrete, what, if anything, is guaranteed about what selfAssign
does?
template<class T> std::vector<T> selfAssign(std::vector<T> v) { v = std::move(v); return v; }
std::move is used to indicate that an object t may be "moved from", i.e. allowing the efficient transfer of resources from t to another object. In particular, std::move produces an xvalue expression that identifies its argument t . It is exactly equivalent to a static_cast to an rvalue reference type.
std::move is actually just a request to move and if the type of the object has not a move constructor/assign-operator defined or generated the move operation will fall back to a copy.
The move assignment operator is different than a move constructor because a move assignment operator is called on an existing object, while a move constructor is called on an object created by the operation. Thereafter, the other object's data is no longer valid.
We know that std::move does not actually move anything. It just cast an lvalue reference (&) to rvalue reference (&&).
17.6.4.9 Function arguments [res.on.arguments]
1 Each of the following applies to all arguments to functions defined in the C++ standard library, unless explicitly stated otherwise.
...
- If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument. [ Note: If the parameter is a generic parameter of the form T&& and an lvalue of type A is bound, the argument binds to an lvalue reference (14.8.2.1) and thus is not covered by the previous sentence. — end note ] [ Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argument move(x)), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was anlvalue. —endnote]
So, the implementation of std::vector<T, A>::operator=(vector&& other)
is allowed to assume that other
is a prvalue. And if other
is a prvalue, self-move-assignment is not possible.
What is likely to happen:
v
will be left in a resource-less state (0 capacity). If v
already has 0 capacity, then this will be a no-op.
Update
The latest working draft, N4618 has been modified to clearly state that in the MoveAssignable
requirements the expression:
t = rv
(where rv
is an rvalue), t
need only be the equivalent value of rv
prior to the assignment if t
and rv
do not reference the same object. And regardless, rv
's state is unspecified after the assignment. There is an additional note for further clarification:
rv
must still meet the requirements of the library component that is using it, whether or nott
andrv
refer to the same object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With