Astinog
Astinog

Reputation: 1181

Undefined behavior with std::move

From the move page of the cppreference

Unless otherwise specified, all standard library objects that have been moved from are placed in a valid but unspecified state. That is, only the functions without preconditions, such as the assignment operator, can be safely used on the object after it was moved from

So, from the example on the same page, this code below is considered undefined behaviour

vector<string> v_string;
string example = "example";
v_string.push_back(move(example));
cout << example << endl;

MSVC will output nothing on the console, but if I do this

vector<int> v_int;
int number = 10;
v_int.push_back(move(number));
cout << number << endl;

will output 10. Is there a reason why this happens? Or is it always undefined behavior?

Upvotes: 9

Views: 2629

Answers (3)

nwp
nwp

Reputation: 9991

That is because a string can be efficiently moved from by stealing the pointer that points to the actual characters, so thats what compilers do, leaving the moved from string "empty". An int cannot be efficiently moved, you just make a copy. Therefore the old int is still there. But that is off the record. Just do not use objects that you moveed from and don't rely on unspecified behavior.

Upvotes: 3

Joe
Joe

Reputation: 6757

Unspecified does not mean undefined.

According to the C++11 standard, section 17.3.26:

valid but unspecified state an object state that is not specified except that the object’s invariants are met and operations on the object behave as specified for its type

As the object is in a valid state, you can stream it to an output, as streaming has no additional preconditions. However what is printed is unspecified, so it may just print nothing, or print that your father smells of elderberries. What you can not safely do is use a function with additional preconditions such as back() which additionally requires the string to be non-empty. Valid strings can be empty.

Containing the old value is a perfectly acceptable option for the unspecified but valid state. In case of fundamental types such as int a simple copy is just the most efficient way to perform a move.

It should also be noted that int is not a standard library object, but a fundamental type (as defined in section 3.9.1). Therefore your quote does not apply.

Upvotes: 13

Jens
Jens

Reputation: 9406

Undefined behavior just means

behavior for which this International Standard imposes no requirements. Permissible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message). Many erroneous program constructs do not engender undefined behavior; they are required to be diagnosed.

If you are interested, take a look at "What every C programmer should know about undefined behavior". It is really an eye-opener.

In your case, it is not undefined behavior but unspecified state: In 21.4.2.16, the C++ standard defines the move constructor's semantics:

Constructs an object of class basic_string as indicated in Table 69. The stored allocator is constructed from alloc. In the second form, str is left in a valid state with an unspecified value.

The "second form" is the move constructor, so the string is in an unspecified state.

That means that the object must be in a state that invariants are met, but anything else is unspecified. For a string, any content would be ok.

Upvotes: 0

Related Questions