Is there any advantage to using an r value reference when you create an object, that would otherwise be in a normal local variable?
Foo&& cn = Foo();
cn.m_flag = 1;
bar.m_foo = std::move(cn);
//cn is not used again
Foo cn;
cn.m_flag = 1;
bar.m_foo = std::move(cn); //Is it ok to move a non rvalue reference?
//cn is not used again
In the first code snippet, it seems clear that there will not be any copies, but I'd guess that in the second the compile would optimize copies out?
Also in the first snippet, where is the object actually stored in memory (in the second it is stored in the stack frame of the enclosing function)?
Those code fragments are mostly equivalent. This:
Foo&& rf = Foo();
is binding a temporary to a reference, which extends the lifetime of the temporary to that of the reference. The Foo
will only be destroyed when rf
goes out of scope. Which is the same behavior you get with:
Foo f;
with the exception that in the latter example f
is default-initialized but in the former example rf
is value-initialized. For some types, the two are equivalent. For others, they are not. If you had instead written Foo f{}
, then this difference goes away.
One remaining difference pertains to copy elision:
Foo give_a_foo_rv() {
Foo&& rf = Foo();
return rf;
}
Foo give_a_foo() {
Foo f{};
return f;
}
RVO is not allowed to be performed in the first example, because rf
does not have the same type as the return type of give_a_foo_rv()
. Moreover, rf
won't even be automatically moved into the return type because it's not an object so it doesn't have automatic storage duration, so that's an extra copy (until C++20, in which it's an extra move):
Foo f = give_a_foo_rv(); // a copy happens here!
Foo g = give_a_foo(); // no move or copy
it seems clear that there will not be any copies
That depends entirely on what moving a Foo
actually does. If Foo
looks like:
struct Foo {
Foo() = default;
Foo(Foo const& ) = default;
Foo& operator=(Foo const& ) = default;
// some members
};
then moving a Foo
still does copying.
And yes, it is perfectly okay to std::move(f)
in the second example. You don't need an object of type rvalue reference to T
to move
from it. That would severely limit the usefulness of moving.
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