Move semantics when sending object as function's parameter

RippeR picture RippeR · Nov 26, 2014 · Viewed 21.2k times · Source

I'm playing with move constructors and move assignments and i've stumbled on this problem. First code:

#include <iostream>
#include <utility>

class Foo {
    public:
        Foo() {}

        Foo(Foo&& other) {
            value = std::move(other.value);
            other.value = 1; //since it's int!
        }

        int value;

    private:
        Foo(const Foo& other);
};


void Bar(Foo&& x) {
    std::cout << "# " << x.value << std::endl;
}

int main() {
    Foo foo;
    foo.value = 5;

    Bar(std::move(foo));
    std::cout << foo.value << std::endl;

    return 0;
}

To my mind, when i use:

Bar(std::move(foo));

Program should "move" foo object to temp object created using move constructor in Bar function. Doing so would leave foo object's value equal zero. Unfortunatly it seams that object held in Bar function as parameter is some sort of reference, since it doesnt "move" original value but using Bar's parameter i can change it.

Would someone mind expalining me why i see in console:

#5
5

instead of

#5
0 //this should be done by move constructor?

Answer

sehe picture sehe · Nov 26, 2014

An rvalue reference is (surprise:) a reference indeed.

You can move from it, but std::move does not move.

So, if you don't move from it, you'll actually operate on the rvalue object (through the rvalue reference).


The usual pattern would be

void foo(X&& x)
{
    X mine(std::move(x));

    // x will not be affected anymore
}

However, when you do

void foo(X&& x)
{
    x.stuff();
    x.setBooDitty(42);
}

effectively, X&& is just acting as a traditional reference