2011-04-24 11:30:34 8 Comments
Is there a reason when a function should return a RValue Reference? A technique, or trick, or an idiom or pattern?
MyClass&& func( ... );
I am aware of the danger of returning references in general, but sometimes we do it anyway, don't we (T& T::operator=(T)
is just one idiomatic example). But how about T&& func(...)
? Is there any general place where we would gain from doing that? Probably different when one writes library or API code, compared to just client code?
Related Questions
Sponsored Content
6 Answered Questions
[SOLVED] C++11 rvalues and move semantics confusion (return statement)
- 2011-02-13 20:28:46
- Tarantula
- 97634 View
- 416 Score
- 6 Answer
- Tags: c++ c++11 move-semantics rvalue-reference c++-faq
16 Answered Questions
2 Answered Questions
[SOLVED] Is returning by rvalue reference more efficient?
- 2009-07-12 18:44:43
- Neil G
- 58187 View
- 120 Score
- 2 Answer
- Tags: c++ c++11 rvalue-reference
3 Answered Questions
[SOLVED] Some clarification on rvalue references
- 2010-04-05 09:08:01
- Dennis Zickefoose
- 1583 View
- 10 Score
- 3 Answer
- Tags: c++ c++11 rvalue-reference
1 Answered Questions
[SOLVED] Why does the rvalue overload of `operator<<` for `basic_ostream` return an lvalue reference?
- 2012-01-12 01:20:03
- Xeo
- 1293 View
- 24 Score
- 1 Answer
- Tags: c++ c++11 iostream rvalue-reference
1 Answered Questions
[SOLVED] Why does get helper of std::tuple return rvalue reference instead of value
- 2015-07-11 17:23:35
- Nir Friedman
- 696 View
- 5 Score
- 1 Answer
- Tags: c++ c++11 stl move-semantics
1 Answered Questions
[SOLVED] How does return by rvalue reference work?
- 2013-05-04 06:18:05
- Yogeshwer Sharma
- 903 View
- 7 Score
- 1 Answer
- Tags: c++11 rvalue-reference
3 Answered Questions
[SOLVED] What is "rvalue reference for *this"?
- 2011-12-22 22:47:58
- ryaner
- 24729 View
- 229 Score
- 3 Answer
- Tags: c++ c++11 move-semantics c++-faq qualifiers
3 Answered Questions
[SOLVED] Move Semantics and Pass-by-Rvalue-Reference in Overloaded Arithmetic
- 2012-10-31 19:21:45
- Tientuinë
- 1794 View
- 12 Score
- 3 Answer
- Tags: c++ c++11 rvalue-reference move-semantics
3 Answered Questions
[SOLVED] Is the introduction of rvalue references actually useful?
- 2013-08-13 07:34:53
- Miklós Homolya
- 440 View
- 0 Score
- 3 Answer
- Tags: c++ c++11 language-design rvalue-reference
5 comments
@CoffeeandCode 2015-07-28 00:03:06
One more possible case: when you need to unpack a tuple and pass the values to a function.
It could be useful in this case, if you're not sure about copy-elision.
Such an example:
pretty rare case unless you're writing some form of
std::bind
orstd::thread
replacement though.@hangyuan 2015-07-27 23:49:18
You can return by reference if you are sure the referenced object will not go out of scope after the function exits, e.g. it's a global object's reference, or member function returning reference to class fields, etc.
This returning reference rule is just same to both lvalue and rvalue reference. The difference is how you want to use the returned reference. As I can see, returning by rvalue reference is rare. If you have function:
You won't like such code:
because it effectively defines ref_a as Type& since named rvalue reference is an lvalue, and no actual move will be performed here. It's quite like:
except that the actual ref_a is a non-const lvalue reference.
And it's also not very useful even you directly pass func() to another function which takes a Type&& argument because it's still a named reference inside that function.
The relationship of func( ) and anotherFunc( ) is more like an "authorization" that func() agrees anotherFunc( ) might take ownership of (or you can say "steal") the returned object from func( ). But this agreement is very loose. A non-const lvalue reference can still be "stolen" by callers. Actually functions are rarely defined to take rvalue reference arguments. The most common case is that "anotherFunc" is a class name and anotherFunc( ) is actually a move constructor.
@Clinton 2011-05-02 04:27:15
This follows up on towi's comment. You never want to return references to local variables. But you might have this:
This should prevent any copies (and possible allocations) in all cases except where both parameters are lvalues.
@sellibitze 2011-05-25 11:24:25
While it's possible, this is generally frowned upon because this approach has its own issues besides saving temporaries. See stackoverflow.com/questions/6006527
@wjl 2011-06-10 16:12:37
Don't those return calls need to use std::move()?
@Clinton 2011-06-11 06:27:19
@wjl: Good question, but I don't think so. std::move works without using std::move. I think the cast to && does the trick here.
@M.M 2015-03-30 02:20:39
@Clinton there's no cast in your code, you have to
return std::move(x2);
etc. Or you could write a cast to rvalue reference type, but that's just whatmove
does anyway.@Aaron McDaid 2015-07-11 19:31:08
@Clinton, I've added in the
move
s. Matt is correct. I've tested it@M.M 2015-07-28 00:04:35
This code is a bad idea (not sure how I overlooked that in my previous comment) because it may return a dangling reference. For example, say you do
vector<N>&& x = vec1 + {1,2,3};
. The second argument will bind to the parametervector<N>&& x2
, however this temporary only lasts for the full-expression it was created in, leavingx
dangling.@M.M 2015-07-28 00:06:44
The code is only correct if the return value is either unused, or assigned to an object -- but then you may as well have returned by value and taken the arguments by value and let copy elision do its thing.
@TemplateRex 2015-09-14 09:05:52
for
vector<N>&& x2
, don't you wantx1 += std::move(x2);
?@Howard Hinnant 2011-04-24 13:54:59
There are a few occasions when it is appropriate, but they are relatively rare. The case comes up in one example when you want to allow the client to move from a data member. For example:
@towi 2011-04-24 14:38:04
An excellent example. The pattern is, you want client code to move something -- allowing him to "steal". Yes, of course.
@Puppy 2011-04-26 14:46:09
Last time I checked, it was undefined to access after moving from.
@Howard Hinnant 2011-04-26 17:07:54
In general a moved from object, when used in the std::lib, must meet all of the requirements specified for whatever part of the std::lib it is using. std-defined types must additionally guarantee that their moved from state is valid. Clients can call any function with that object as long as there are no pre-conditions on its value for said function-call.
@Howard Hinnant 2011-04-26 17:08:31
Finally, in the example above, there are no moved-from objects. std::move doesn't move. It only casts to rvalue. It is up to the client to move (or not) from that rvalue. That client will only access a moved-from value if he dereferences the move_iterator twice, without intervening iterator traversal.
@fredoverflow 2011-05-15 12:33:29
Wouldn't it be safer to use
value_type
instead ofvalue_type&&
as the return type?@Howard Hinnant 2011-05-15 13:39:39
Yes, I think so. However in this case I think the added benefit outweighs the risk. move_iterator is often used in generic code to turn a copying algorithm into a moving one (e.g. a move-version of vector::insert). If you then supply a type with an expensive copy & move to the generic code, you've got an extra copy gratuitously added. I'm thinking array<int, N> for example. When move-inserting a bunch of these into vector, you don't want to accidentally introduce an extra copy. On the risk side,
const X& x = *i
is pretty rare. I don't think I've ever seen it.@Howard Hinnant 2011-05-15 16:21:41
On second thought, no, it wouldn't be safer. Rationale: The danger in returning a reference is that if the reference refers to a temporary, then the temporary can destruct before the reference does, thus leading to a dangling reference. In this example the reference will (almost always) refer to an lvalue. Very few iterators return prvalues, and those that do should probably not be adapted by move_iterator. So in the normal use case, even if the client holds the reference beyond the sequence point, the referred-to object still exists after the sequence point.
@Dave Abrahams 2011-11-30 10:58:42
Well, it's still a wee bit safer to return a value, you have to admit. However, that makes the move eager as opposed to optional (depending on what the client of
operator*
does with it)@Potatoswatter 2013-05-15 09:24:34
Returning by value or rvalue reference aren't comparable in risk, because they do completely different things. Returning by RR is exactly the same as adding
std::move
around the function call, that's all. And since it only makes sense to move an lvalue, use-cases of prvalues are just another story.@ThomasMcLeod 2015-08-04 01:06:06
Is this valid if
*i_
isconst
? Just asking.@Howard Hinnant 2015-08-04 03:48:25
@ThomasMcLeod: If
value_type
is alsoconst
, it is valid, but there will be no moving, just a copy. Ifvalue_type
is notconst
, then you'll get a compile-time error complaining about assigning aconst
value to a non-const reference.@Emile Cormier 2016-03-27 01:21:15
Wouldn't this best be used with an r-value ref qualifier?
@Howard Hinnant 2016-03-27 01:35:56
@EmileCormier: No. The purpose of
move_iterator
is to turn generic "copy" algorithms into "move" algorithms. See open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1771.html and search for "replace_copy".replace_copy
+move_iterator
allows you to buildreplace_move
for yourself. But thereplace_copy
algorithm need do nothing special. It is ignorant of the fact that it is dealing withmove_iterator
. It dereferences this iterator just as it would any other.@Emile Cormier 2016-03-28 16:33:15
@HowardHinnant, sorry I had tunnel vision when I posted that comment. I was only looking at the
operator*
line and didn't pay attention to themove_iterator
class around it.@Puppy 2011-04-24 11:34:34
No. Just return the value. Returning references in general is not at all dangerous- it's returning references to local variables which is dangerous. Returning an rvalue reference, however, is pretty worthless in almost all situations (I guess if you were writing
std::move
or something).@towi 2011-04-24 11:43:33
I think during the early design of the C++0x there was a time when it was suggested that things like the move-assign and
T&& operator+(const T&,T&&)
should return a&&
. But that is gone now, in the final draft. That's why I ask.