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 :(
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&& .
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.
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.
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.
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 ofthis
in a member function of a classX
isX*
. [...]
§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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With