user1299784
user1299784

Reputation: 2097

c++: why does foo(X&) get called instead of foo(X&&)?

Here, creator() returns a pointer to X, which I dereference and pass to foo. Since that's an rvalue, move semantics should be used, right? But when I run it, I find that foo(X&) is called.

#include <iostream>
using namespace std;

struct X {
        int i;
};

void foo(X& x) {
        cout << "foo(X&)" << endl;
}

void foo(X&& x) {
        cout << "foo(X&&)" << endl;
}

struct X* creator() {
        return new X {5};
}

main() {
        X x{5};
        foo(*creator()); // prints foo(X&)
}

Upvotes: 1

Views: 66

Answers (2)

Barry
Barry

Reputation: 302827

It's helpful to think of things in terms of identity and movability:

  • Has identity and cannot be moved from? lvalue
  • Has identity and can be moved from? xvalue
  • No identity? prvalue

Dereferencing a pointer yields an expression that has an identity, that cannot be moved from, so it's an lvalue. Hence, it matches the X& overload.

If you want to call the other overload, you will have to annotate the expression to indicate that it's safe to be moved from. This is what std::move is for. Once you do that, the expression becomes an xvalue and now matches the X&& overload.

Upvotes: 3

Sam Varshavchik
Sam Varshavchik

Reputation: 118310

creator() returns a pointer.

Dereferencing that pointer gets you an lvalue. Pointer dereference results in an lvalue. After all, if p is a pointer, you can assign to it: *p=some_value, and you can only assign to an lvalue, therefore it has to be an lvalue.

You are getting confused by two things. It is true that the function returns an rvalue. But you're not passing what the function returns. The function returns a pointer, and you are dereferencing the pointer, which results in an lvalue.

Upvotes: 3

Related Questions