Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about r-value references

#include <iostream>

class Foo { };

Foo createFoo() { return Foo(); }

void bar(Foo &&) { std::cout << "in bar(Foo &&)\n"; }

void bar(Foo const &) { std::cout << "in bar(Foo const &)\n"; }

void baz(Foo &&f) {
    std::cout << "in baz, ";
    bar(f);
    // bar(std::move(f));
}

int main()
{
    baz(createFoo());
    return 0;
}

My expected output is: in baz, in bar(Foo &&), but I'm getting: in baz, in bar(Foo const &). If I switch the calls to bar (see the comment) I get the expected output, but this seems wrong to me. Is there some reason the compiler can't call bar(Foo &&) without me converting a Foo&& to a Foo&&?

Thanks in advance!

like image 236
Stephen Newell Avatar asked Dec 04 '22 03:12

Stephen Newell


2 Answers

Inside baz(Foo&& f), f is an lvalue. Therefore, to pass it on to bar as an rvalue reference you have to cast it to an rvalue. You can do this with a static_cast<Foo&&>(f), or with std::move(f).

This is to avoid accidentally moving things multiple times in the same function e.g. with multiple calls to bar(f) inside baz.

like image 123
Anthony Williams Avatar answered Dec 15 '22 14:12

Anthony Williams


In short, the rule is that a named rvalue reference is an lvalue. This is to prevent automatically moving out of a named variable that you then need to use later. In contrast unnamed temporaries can never be used again and so can be automatically moved from.

I found this series http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ to be pretty helpful even though it's a little bit old.

like image 33
Mark B Avatar answered Dec 15 '22 13:12

Mark B