Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What exactly happens when we use rvalue references and how does std::move work?

I am trying to understand rvalue reference and move semantics. In following code, when I pass 10 to Print function it calls rvalue reference overload, which is expected. But what exactly happens, where will that 10 get copied (or from where it referred). Secondly what does std::move actually do? Does it extract value 10 from i and then pass it? Or it is instruction to compiler to use rvalue reference?

void Print(int& i)
{
    cout<<"L Value reference "<<endl;
}

void Print(int&& i)
{
    cout<<"R Value reference "<< endl;
}

int main()
{
    int i = 10;

    Print(i); //OK, understandable
    Print(10); //will 10 is not getting copied? So where it will stored

    Print(std::move(i)); //what does move exactly do

    return 0;
}

Thanks.

like image 669
Pranit Kothari Avatar asked Oct 01 '13 06:10

Pranit Kothari


2 Answers

In the case of a 10, there will probably be optimisations involved which will change the actual implementation, but conceptually, the following happens:

  • A temporary int is created and initialised with the value 10.

  • That temporary int is bound to the r-value reference function parameter.

So conceptually, there's no copying - the reference will refer to the temporary.

As for std::move(): there may be some tricky bits related to references etc., but principally, it's just a cast to r-value reference. std::move() does not actually move anything. It just turns its argument into an r-value, so that it can be moved from.

"Moving" is not really a defined operation, anyway. While it's convenient to think about moving, the important thing is l-value vs. r-value distinction.

"Moving" is normally implemented by move constructors, move assignment operators and functions taking r-value references (such as push_back()). It is their implementation that makes the move an actual move - that is, they are implemented so that they can "steal" the r-value's resources instead of copying them. That's because, being an r-value, it will no longer be accessible (or so you promise the compiler).

That's why std::move() enables "moving" - it turns its argument into an r-value, signalling, "hey, compiler, I will not be using this l-value any more, you can let functions (such as move ctors) treat it as an r-value and steal from it."

like image 193
Angew is no longer proud of SO Avatar answered Nov 15 '22 05:11

Angew is no longer proud of SO


But what exactly happens, where that 10 will get copied (or from where it referred)

A temporary value is created, and a reference passed to the function. Temporaries are rvalues, so can be bound to rvalue references; so the second overload is chosen.

Secondly what std::move actually do?

It gives you an rvalue reference to its argument. It's equivalent (by definition) to static_cast<T&&>.

Despite the name, it doesn't do any movement itself; it just gives you a reference that can be used to move the value.

like image 30
Mike Seymour Avatar answered Nov 15 '22 05:11

Mike Seymour