What I wish to do (using a C++ lambda) is effectively:
std::vector<MyType> GetTheArray () {return something;}
const auto DoSomething = [](std::vector<MyType> & array)
{
//Some processing that involves either sorting the 'array' or setting temporary flags on the items
};
DoSomething (GetTheArray ());
This appears to be disallowed in standard C++ because the rvalue cannot be passed as a non-const reference.
My questions:
1) Is there a way to do this using a type-cast or am I obliged to create a temporary variable to store the results of GetTheArray ()?
2) Is there a good reason why this is disallowed in C++?
Please note that the 'something' returned from 'GetTheArray' is an array that is constructed on the fly, not a stored value.
It seems from the comments that what you want is to take a vector, modify it destructively (in the sense that the original state cannot be reset) and then use the result internally. And you want this to work efficiently for both lvalues and rvalues.
The next question is whether in the case of the lvalue, the code that holds the original container needs it after the function call has completed, and if it needs the original state of the vector or not. Depending on the answers to that you have different solutions:
The caller holding an lvalue does not use it anymore after the call
(or alternatively, the caller holding the lvalue needs the original state)
This is the simplest case. Then your function should take the container by value. If the caller has an lvalue, it can std::move
to avoid the copy (it does not care about the object anymore) or copy which might be more expensive but leaves the original container untouched.
If the function is called with an rvalue then the copy will be either elided or transformed into a cheap implicit move.
The caller holding the lvalue does not need the original state, but it needs the container
This case is the hard one, and you will need to provide two overloads for the same function (or lambda), one taking an lvalue to be used by this caller and a different taking an rvalue-reference for the case where the caller hands a temporary. In both cases the binding will be cheap. While this requires more code, you can implement one overload in terms of the other:
rtype f(std::vector<Data> & ); // for lvalues
rtype f(std::vector<Data> && v) // for rvalues
{ return f(v); } // v is an lvalue here
The fact that you are doing lambdas might make this slightly more complicated, but hopefully not too much.
If you for some reason you really want to modify something
you could always copy the temporary into your lambda.
const auto DoSomething = [](std::vector<MyType> array) { /*whatever*/ }
The way you call your lambda a compiler might be able to elide the copy. C++11 move semantics formalize this.
(Actually, @honk beat me to it as regards passing-by-value. To be different, I'll extend my answer to discuss using &&
explicitly)
Drop the &
, and just pass it by value instead.
You're using lambdas, therefore you're using c++11, therefore you should just pass it by value. Yes, it will be just as fast.
C++11 is very good at noticing when a temporary is being 'copied'. It will replace the copy with a move. It will then be fast, and arguably it will be easier to read.
So, even though you might know nothing about &&
and std::move
and so on, it's safe to say that you should start moving towards passing things by value instead of by reference. It will lead to more readable code, and it shouldn't lead to a slowdown if used at the right time.
Basically, it's fast if you pass a temporary value, such as that returned by a function, into a function, but only if you are using a standard container such as vector
. Otherwise, you'll need to write your own &&
-aware constructors to take advantage of the possible speed up.
Update: If you're determined to force it to be by reference, and/or you are using custom containers, then you could replace &
with &&
. This will allow you to pass a non-const reference. This is called a rvalue-reference.
As has been pointed out by many others, the temporary will be destroyed just after DoSomething
returns. Bear this in mind. It means that you will want to fully consume the contents of the array before it returns. Maybe you print it to the screen, or store it in a database. Alternatively, you might copy or move the data into another object and return that.
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