mercury0114
mercury0114

Reputation: 1449

What happens when std::move is called on a rvalue reference?

Consider the following c++ programs:

string construct(string&& s) {
    // Passing a r-value reference as an argument to the assignment operator
    string constructed = s;
    return constructed;
}

int main() {
    string original = "Hello";
    string temp1 = construct(std::move(original));

    printf("%s\n", original.c_str()); // Prints "Hello", so original has not changed
    return 0;
}

Now a small change that I perform is calling std::move on an r-value reference argument:

string constructWithMove(string&& s) {
    // Passing a cast to an r-value reference using r-value reference as an argument.
    string constructed = std::move(s);
    return constructed;
}

int main() {
    string original = "Hello";
    string temp = constructWithMove(std::move(original));

    printf("%s\n", original.c_str()); // Prints "", original is set to the empty string, WHY???
    return 0;
} 

So it looks like casting an r-value reference to an r-value reference induces something peculiar. Why in the first case the original string retains its value but not in the second?

Upvotes: 3

Views: 3498

Answers (3)

n. m. could be an AI
n. m. could be an AI

Reputation: 119847

string constructed = s;

This does not cause a move because s is not an rvalue. It is an rvalue reference, but not an rvalue. If it has a name, it is not an rvalue. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression.

string constructed = std::move(s);

This causes a move because std::move(s) is an rvalue: it's a temporary and its type is not lvalue reference.

There are no other moves in the program (std::move is not a move, it's a cast).

Upvotes: 2

eerorika
eerorika

Reputation: 238301

What happens when std::move is called on a rvalue reference?

std::move casts the argument into an rvalue reference, which it returns.

Is std::move(r_value_reference_argument) undefined

No.


// Prints "", original is set to the empty string, WHY???

What's happening here?

Because the result from std::move is an r-value (x-value to be more specific). And being passed to a constructor of std::string, it invokes the move constructor. You are observing a string that was moved from.

Note that this moving leaves the original string in an unspecified state. It is not guaranteed to be empty, nor even different from what it used to contain. Neither is it guaranteed to not be empty.


OK, but why in the first case the original string is not empty?

Because s is an lvalue1, and therefore the copy constructor was used. The copy constructor leaves the original string unmodified.

1 Easy rule of thumb: If it is a name, then it is an l-value.

Upvotes: 7

user2039981
user2039981

Reputation:

// Prints "", original is set to the empty string, WHY???

Because you moved it.

Upvotes: 2

Related Questions