What would be a valid use case for a signature like this?:
T&& foo();
Or is the rvalue ref only intended for use as argument?
How would one use a function like this?
T&& t = foo(); // is this a thing? And when would t get destructed?
What would be a valid use case for a signature like this?:
T&& foo();
Or is the rvalue ref only intended for use as argument?
How would one use a function like this?
T&& t = foo(); // is this a thing? And when would t get destructed?
For a free function it doesn't make much sense to return a rvalue reference. If it is a non-static local object then you never want to return a reference or pointer to it because it will be destroyed after the function returns. It can possibly make sense to return a rvalue reference to an object that you passed to the function though. It really depends on the use case for if it makes sense or not.
One thing that can greatly benefit from returning an rvalue reference is a member function of a temporary object. Lets say you have
class foo
{
std::vector<int> bar;
public:
foo(int n) : bar(n) {}
std::vector<int>& get_vec() { return bar; }
};
If you do
auto vec = foo(10).get_vec();
you have to copy because get_vec
returns an lvalue. If you instead use
class foo
{
std::vector<int> bar;
public:
foo(int n) : bar(n) {}
std::vector<int>& get_vec() & { return bar; }
std::vector<int>&& get_vec() && { return std::move(bar); }
};
Then vec
would be able to move the vector returned by get_vec
and you save yourself an expensive copy operation.
get_vec
case? If you return by value you incur 2 move operations. Passing by rvalue reference you only have 1 move. –
Indreetloire get_vec()&&
you're returning an rvalue reference to what might be a temporary object (e.g. if used with a materialized prvalue). It would be much safer (and is recommended) to return by value. Any decent compiler will elide the extraneous constructor calls. –
Transmissible get_vec() &&
on a temporary object so it's safe to call it. –
Indreetloire std::move(a).get_vec()
). My point is that you're potentially returning a reference to an object that's about to be destroyed. It's the same problem as returning a reference to a local function variable. –
Transmissible std::vector<int> get_vec() && { return std::move(bar); }
in this case ends up being better 999/1000. Can you come up with a better example? –
Wiggs std::vector<int> get_vec() &&
, not std::vector<int>&& get_vec() &&
. –
Novgorod std::vector<int>&& get_vec() &&
. My code is: auto &&v = std::move(a).get_vec();
auto &&
should be always safe but in this case it will capture only reference and does not prolong lifetime of a
. See e.g. #10191177 –
Borstal a
still exists, so v
is still a valid reference to a
s internal vector. –
Indreetloire auto bar = foo{42}.get_vec();
–
Indreetloire auto &&bar = foo{42}.get_vec();
than to my example with move
above. –
Borstal &&
, why e.g. std::optional
is doing exactly this in operator*()
? –
Borstal std::optional<expensive> bar() { ... } auto foo = *bar()
and now the wrapped expensive
object is moved instead of copied. –
Indreetloire std::optional::operator*
was T operator*() &&
, then auto foo = *bar()
would do two moves (possibly optimizable), still no copy. –
Borstal T&& t = foo(); // is this a thing? And when would t get destructed?
An rvalue reference is really similar to a lvalue reference. Think about your example like it was normal references:
T& foo();
T& t = foo(); // when is t destroyed?
The answer is that t
is still valid to use as long as the object is refers to lives.
The same answer still applies to you rvalue reference example.
But... does it make sense to return an rvalue reference?
Sometimes, yes. But very rarely.
consider this:
std::vector<int> v = ...;
// type is std::tuple<std::vector<int>&&>
auto parameters = std::forward_as_tuple(std::move(v));
// fwd is a rvalue reference since std::get returns one.
// fwd is valid as long as v is.
decltype(auto) fwd = std::get<0>(std::move(parameters));
// useful for calling function in generic context without copying
consume(std::get<0>(std::move(parameters)));
So yes there are example. Here, another interesting one:
struct wrapper {
auto operator*() & -> Heavy& {
return heavy;
}
auto operator*() && -> Heavy&& {
return std::move(heavy);
}
private:
Heavy instance;
};
// by value
void use_heavy(Heavy);
// since the wrapper is a temporary, the
// Heavy contained will be a temporary too.
use_heavy(*make_wrapper());
wrapper
instance you use this on is a temporary, operator*()
returns a reference to instance
, which is likewise a temporary. So after the function returns you have a reference to an object whose lifetime has ended (undefined behavior). –
Transmissible decltype(auto) fwd = std::get<0>(std::move(parameters));
? –
Wiggs T&& std::optional<T>::operator*() &&
is defined to behave exactly as proposed by @GuillaumeRacicot. I would expect T std::optional<T>::operator*() &&
but it is not this way... –
Borstal I think a use case would be to explicitly give permission to "empty" some non-local variable. Perhaps something like this:
class Logger
{
public:
void log(const char* msg){
logs.append(msg);
}
std::vector<std::string>&& dumpLogs(){
return std::move(logs);
}
private:
std::vector<std::string> logs;
};
But I admit I made this up now, I never actually used it and it also can be done like this:
std::vector<std::string> dumpLogs(){
auto dumped_logs = logs;
return dumped_logs;
}
return std::move(logs);
where the return value is a reference type and *this
is a temporary (due to being an rvalue method) makes this->logs
a temporary as well. That's the reference to a temporary I mean. –
Transmissible auto&& x = Logger{}.dumpLogs();
? Yes, that is dangling reference, but that happens for all getters no matter what type of reference they return. My use case would be something like Logger l; /*calls to log()*/, auto logs = l.dumpLogs();/*log again.. and repeat.*/
–
Ergot © 2022 - 2024 — McMap. All rights reserved.
std::move
comes to mind. It certainly returnsT&&
. Edit :std::optional::value
also has anT&&
overload. Edit 2 : It also has aconst T &&
overload, though I'll admit I don't understand the meaning. – Overhaulstd::get
family of functions, too. – Botanical