I have a move-only struct Foo
, and a function Foo get();
If I want to capture the return value of get
in a mutable manner, I have two options:
Foo
)Foo&&
)When I capture by rvalue-reference I create an lvalue, much like capturing by value.
I'm struggling to see the point between the different options?
Working example:
#include <iostream>
struct Foo
{
Foo(std::string s) : s(std::move(s)) {}
Foo(Foo&& f) : s(std::move(f.s)) {}
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
std::string s;
};
Foo get()
{
return Foo { "hello" };
}
int main()
{
// capture return value as l-value
Foo lv1 = get();
// move into another lvalue
Foo lv2 = std::move(lv1);
std::cout << lv2.s << '\n';
// capture return value as r-value reference
Foo&& rv1 = get();
// move into another lvalue
Foo lv3 = std::move(rv1);
std::cout << lv3.s << '\n';
return 0;
}
Foo lv1 = get();
This requires that Foo
is copy/moveable.
Foo&& rv1 = get();
This does not (at least, not as far as this line of code is concerned; the implementation of get
may still require one).
Even though compilers are permitted to elide the copy of the return value into the variable, copy initialization of this form still requires the existence of an accessible copy or move constructor.
So if you want to impose as few limitations on the type Foo
as possible, you can store a &&
of the returned value.
Of course, C++17 changes this rule so that the first one doesn't need a copy/move constructor.