No, this is not undefined behavior, it is going to be implementation defined behavior, it will depend on how move assignment is implemented.
Relevant to this is LWG issue 2468: Self-move-assignment of library types , note this is an active issue and does not have an official proposal so this should be considered indicative rather than definitive, but it does point out the sections that are involved for the standard library and points out they currently conflict. It says:
Suppose we write
vector<string> v{"a", "b", "c", "d"}; v = move(v);What should be the state of v be? The standard doesn’t say anything
specific about self-move-assignment. There’s relevant text in several
parts of the standard, and it’s not clear how to reconcile them.[…]
It’s not clear from the text how to put these pieces together, because it’s not clear which one takes precedence. Maybe 17.6.4.9 [res.on.arguments] wins (it imposes an implicit precondition that isn’t mentioned in the MoveAssignable requirements, so v = move(v) is undefined), or maybe 23.2.1 [container.requirements.general] wins (it explicitly gives additional guarantees for Container::operator= beyond what’s guaranteed for library functions in general, so v = move(v) is a no-op), or maybe something else.
On the existing implementations that I checked, for what it’s worth, v = move(v) appeared to clear the vector; it didn’t leave the vector unchanged and it didn’t cause a crash.
and proposes:
Informally: change the MoveAssignable and Container requirements tables (and any other requirements tables that mention move assignment, if any) to make it explicit that x = move(x) is defined behavior and it leaves x in a valid but unspecified state. That’s probably not what the standard says today, but it’s probably what we intended and it’s consistent with what we’ve told users and with what implementations actually do.
Note, for built-in types this is basically a copy, we can see from draft C++14 standard section 5.17 [expr.ass]:
In simple assignment (=), the value of the expression replaces that of the object referred to by the left
operand.
which is different than the case for classes, where 5.17 says:
If the left operand is of class type, the class shall be complete. Assignment to objects of a class is defined
by the copy/move assignment operator (12.8, 13.5.3).
Note, clang has a self move warning:
Log:
Add a new warning, -Wself-move, to Clang.-Wself-move is similiar to -Wself-assign. This warning is triggered when
a value is attempted to be moved to itself. See r221008 for a bug that
would have been caught with this warning.