a little question about rvalue reference overloading

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&&)?
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.
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));
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
Topic archived. No new replies allowed.