a little question about rvalue reference overloading

Jul 28, 2014 at 2:06pm
here's one snippet from MSDN
///////////////////////////////////////////
class MemoryBlock
{
// TODO: Add resources for the class here.
};

void f(const MemoryBlock&)
{
cout << "In f(const MemoryBlock&). This version cannot modify the parameter." << endl;
}

void f(MemoryBlock&&)
{
cout << "In f(MemoryBlock&&). This version can modify the parameter." << endl;
}

int main()
{
MemoryBlock block;
f(block);
f(MemoryBlock());
}
/////////////////////////////////
what confuses me is that block isn't declared as a const nor its a rvalue(I suppose?), why f(block) calls the const version instead of the normal void f(MemoryBlock&&)?
Jul 28, 2014 at 5:08pm
I believe that the compiler knows that the MemoryBlock in the second call is not going to be used in main(). Thus, it can use move semantics.
Jul 28, 2014 at 5:20pm
If you want to use move semantics on a value that is not a temporary, you must indicate to the compiler that you wish to do so.

f(std::move(block));
Jul 28, 2014 at 6:37pm
NOTE: Explaining rvalue-ref within few lines of comment cannot suffice, I advise you read more about it or perhaps learn from the experts.

MemoryBlock {} or MemoryBlock() creates a temporary object whose lifetime doesn't exceed where they're used. Rvalue, loosely speaking, appears on the rhs of an expression OR are basically objects with a short lifespan such as when you create temporaries(object created on the fly or the result of a function call) or a moved-from object(usually via std::move()). Rvalue references is a C++11 "feature" that allows temporary objects to be bind, such that their lifespan can be "prolonged." Thus, the name - rvalue reference( reference to an rvalue object ).

Your question is quite simple, so I'm gonna rephrase: How does the compiler choose an overloaded function for rvalue-ref and lvalues?

Since we know that when you create a temporary, or a moved-from object, they can be bound to an rvalue-reference. The compiler checks the type of the object in the argument list(s) and says "is this a temporary object or an lvalue?" For the latter it choose a cv-qualified ref, otherwise if the former is the case, it choose an rvalue ref. See the below example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//necessary headers, and I assume print() outputs to the output stream

struct T;

void f( T && a ){
    print(rvalue);
}
void f( const T & a) {
    print(lvalue);
}
T T_factory() {
    return T {};
}
int main(){
    T t_object;
    f( t_object ); //calls f( const T &), t_object is an lvalue
    f( T_factory() ); //calls f( T && )
    f( std::move(t_object) ); //calls f(T && )
    //note that t_object is in an unsafe state, careful!
}


If function f() wasn't overloaded with an rvalue-ref of that same object, all calls to f() would choose the cv-qualified version of f().
Last edited on Jul 28, 2014 at 6:43pm
Topic archived. No new replies allowed.