Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Move from *this in an rvalue method?

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 :(

like image 512
fredoverflow Avatar asked Jun 12 '10 12:06

fredoverflow


People also ask

How do you use rvalue reference?

If the function argument is an rvalue, the compiler deduces the argument to be an rvalue reference. For example, assume you pass an rvalue reference to an object of type X to a template function that takes type T&& as its parameter. Template argument deduction deduces T to be X , so the parameter has type X&& .

What is R value Referene in C++11?

An rvalue reference is a reference that will bind only to a temporary object. What do I mean? Prior to C++11, if you had a temporary object, you could use a "regular" or "lvalue reference" to bind it, but only if it was const: 1. 2.

What's the need to move semantics?

Move semantics is about transferring resources rather than copying them when nobody needs the source value anymore. In C++03, objects are often copied, only to be destroyed or assigned-over before any code uses the value again.

Can you return an rvalue?

Returning a value from a function will turn that value into an rvalue. Once you call return on an object, the name of the object does not exist anymore (it goes out of scope), so it becomes an rvalue. Similarly, calling a function will give back an rvalue. The return value of a function has no name.


1 Answers

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

like image 158
Xeo Avatar answered Sep 22 '22 00:09

Xeo