Arrays can not be returned by value from function (only by reference/constant reference) both in C++03 and C++11 (because we can not assign one array to another directly):
const size_t N = 10;
using Element = int;
using Array = Element[N];
Array array;
// does not compile
// Array GetArray()
// {
// return array;
// }
Array& GetArrayRef()
{
return array;
}
In C++ there was introduced a new reference type - rvalue reference. It can be used with arrays, too:
void TakeArray(Array&& value)
{
}
// ...
TakeArray(std::forward<Array>(array));
TakeArray(std::forward<Array>(GetArrayRef()));
What is the purpose of such reference (rvalue reference to an array)? Can it be used in any real code or is it only a defect of C++11 standard?
An rvalue reference is a promise by either the programmer or compiler that the data being referred to is about to be disposed of1, and that the reader changing it in reasonable ways is acceptable if it makes reading faster (among other things).
If you are copying from an array of vector
with the above promise, you can clearly move
the contained vector
s for a possibly massive performance boost.
So no, this is not a defect.
std::vector<int> data[1000];
void populate_data() {
for( auto& v : data )
v.resize(1000);
}
template<std::size_t N>
std::vector< std::vector<int> > get_data( std::vector<int>(&&arr)[N] ) {
std::vector< std::vector<int> > retval;
retval.reserve(N);
for( auto& v : arr )
retval.emplace_back( std::move(v) );
return retval;
}
template<std::size_t N>
std::vector< std::vector<int> > get_data( std::vector<int>(const&arr)[N] ) {
std::vector< std::vector<int> > retval;
retval.reserve(N);
for( auto const& v : arr )
retval.emplace_back( v );
return retval;
}
int main() {
populate_data();
auto d = get_data(data); // copies the sub-vectors
auto d2 = get_data( std::move(data) ); // moves the sub-vectors
}
in this case, things are a bit contrived, but in general the source of the data could be move
d from or not. The rvalue override does a move of the sub-data if the entire container is move
d from (an rvalue reference), and otherwise does a copy.
With a bit more work, we could write the above so that it all happens in one method. So if we have an rvalue container (aka owning range), and the container itself isn't suitable for being moved from directly, we move
the contents. But that is just advanced metaprogramming, and not essential to the answer.
1 The compiler does this in restricted situations involving the object being "impossible" to reference after the use, either because it is an anonymous temporary or because it is being used in certain circumstances in return values of functions. (It is not actually impossible, and in theory this C++11 feature could break pre-C++11 code, but it is pretty close). Programmers do this by an rvalue cast. What exactly it means that it will be "disposed of immediately" depends on context, but the general rule is that the consumer of the rvalue reference can put the object into any "valid" state that can still be destroyed and interacted with. The existence of rvalue-based swap
means that putting it into a state that can only be destroyed is not safe.
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