Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is x = std::move(x) undefined?

Let x be a variable of some type that has been previously initialized. Is the following line:

x = std::move(x) 

undefined? Where is this in the standard and what does it say about it?

like image 711
becko Avatar asked Jul 21 '15 19:07

becko


People also ask

What does std :: move () do?

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.

What does move () do in C++?

std::move in C++Moves the elements in the range [first,last] into the range beginning at result. The value of the elements in the [first,last] is transferred to the elements pointed by result. After the call, the elements in the range [first,last] are left in an unspecified but valid state.

Where is std :: move defined?

In C++11, std::move is a standard library function that casts (using static_cast) its argument into an r-value reference, so that move semantics can be invoked. Thus, we can use std::move to cast an l-value into a type that will prefer being moved over being copied. std::move is defined in the utility header.

Does STD move invalidate pointers?

Does std::move invalidate pointers? No. An object still exists after being moved from, so any pointers to that object are still valid.


2 Answers

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.

like image 126
Shafik Yaghmour Avatar answered Sep 23 '22 15:09

Shafik Yaghmour


It will call X::operator = (X&&), so it is up to the implementation to manage this case (as it is done for X::operator = (const X&))

like image 26
Jarod42 Avatar answered Sep 22 '22 15:09

Jarod42