Example code:
#include <iostream>
int main()
{
std::vector<int> w(20, 123), x;
w = std::move(w);
std::cout << w.size() << std::endl;
}
Output on g++ 4.8.3: 0
Of course, the standard says that the move-assignment operator leaves the operand in an unspecified state. For example if the code were x = std::move(w);
then we would expect w.size()
to be zero.
However, is there a specified ordering or other clause that covers the self-move case? Is it unspecified whether size is 0
or 20
, or something else, or undefined behaviour? Do the standard containers have any defined semantics here?
Related: this thread talks about whether you should care about self-move in your own classes, but does not discuss whether standard containers' move-assignment operators do, and doesn't provide Standard references.
NB. Is this exactly identical to w = static_cast< std::vector<int> && >(w);
or does the fact that std::move
is a function make a difference?
A move assignment is less, not more restrictively defined than ordinary assignment; where ordinary assignment must leave two copies of data at completion, move assignment is required to leave only one. If no user-defined move assignment operators are provided for a class type ( struct, class, or union ), and all of the following is true:
For non-union class types (class and struct), the move assignment operator performs full member-wise move assignment of the object's direct bases and immediate non-static members, in their declaration order, using built-in assignment for the scalars, memberwise move-assignment for arrays, and move assignment operator for class types.
What target behavior is the focus of your behavior change assignment? The target behavior that I will be focusing on for my behavior change assignment is reducing the amount of time I spend on social media. I chose this specific target behavior as it has become a distraction which has caused me to lack the focus I used to have.
If only the copy assignment is provided, all argument categories select it (as long as it takes its argument by value or as reference to const, since rvalues can bind to const references), which makes copy assignment the fallback for move assignment, when move is unavailable.
§17.6.4.9 [res.on.arguments]:
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 typeA
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 argumentmove(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 an lvalue. — end note ]
Since "the implementation may assume that this parameter is a unique reference to this argument", and self-move-assignment would violate this assumption, it has undefined behavior.
See also LWG issue 1204.
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