11

In C++11, methods can be overloaded on whether or not the expression that denotes the object on which the method is called is an lvalue or an rvalue. If I return *this from a method called via an rvalue, do I need to explicitly move from *this or not?

Foo Foo::method() &&
{
    return std::move(*this);   // Is this move required or not?
}

Unfortunately, I can't simply test this on my compiler since g++ does not support this feature yet :(

Xeo
  • 129,499
  • 52
  • 291
  • 397
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • I'd expect the `move` to be required, as `this` is a named rvalue, similar to if a function takes a rvalue parameter. But not making it an answer since I can't quote chapter and verse on it :) – jalf Jun 12 '10 at 12:40
  • @jalf: And I would expect the move to be required since generally `*E` is an lvalue, but who knows :) And I have never heard of named rvalues before. Are you sure about "this"? (no pun intended!) – fredoverflow Jun 12 '10 at 12:43
  • A named rvalue is a new term introduced to disambiguate overloaded calls involving references. e.g. if we have `foo(X& x)` and `foo(X&& x)`, what does `foo(someX)` call, i.e is `someX` an `X&` or an `X&&`? The answer is `X&` because `someX` has a name -- it is a named rvalue, which is an `X&`. If we called `foo(someX + something)` then it would be an `X&&` because expressions don't have "names". – Peter Alexander Jun 12 '10 at 14:15
  • "is `someX` an `X&` or an `X&&`?" -> Erm, neither? It is an X :) I don't see how `someX` is anything but an lvalue... – fredoverflow Jun 12 '10 at 15:02

1 Answers1

5

The type of *this is always an lvalue:

§9.3.2 [class.this] p1

In the body of a non-static (9.3) member function, the keyword this is a prvalue expression whose value is the address of the object for which the function is called. The type of this in a member function of a class X is X*. [...]

§5.3.1 [expr.unary.op] p1

The unary * operator performs indirection: the expression to which it is applied shall be a pointer to an object type, or a pointer to a function type and the result is an lvalue referring to the object or function to which the expression points.

So you will need to std::move if you want to invoke the move constructor.

The following code snippet shows that:

#include <iostream>
#include <utility>

struct test{
  test(){}
  test(test const&){ std::cout << "copy ctor // #1\n"; }
  test(test&&){ std::cout << "move ctor // #2\n"; }

  test f_no_move() &&{ return *this; }
  test f_move() &&{ return std::move(*this); }
};

int main(){
  test().f_no_move(); // #1
  test().f_move(); // #2
}

Using Clang 3.1 (the only compiler I know that implements ref-qualifiers), I get the following output:

$ clang++ -std=c++0x -stdlib=libc++ -pedantic -Wall t.cpp
$ ./a.out
copy ctor // #1
move ctor // #2

Xeo
  • 129,499
  • 52
  • 291
  • 397