在C ++ 03和C ++ 11中,不能通过函数的值(仅通过引用/常量引用)返回数组(因为我们不能直接将一个数组分配给另一个数组):
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;
}
在C ++中引入了一种新的引用类型 - 右值引用。它也可以用于数组:
void TakeArray(Array&& value)
{
}
// ...
TakeArray(std::forward<Array>(array));
TakeArray(std::forward<Array>(GetArrayRef()));
此类引用的目的是什么(rvalue引用数组)?它可以用在任何实际代码中,还是仅仅是C ++ 11标准的缺陷?
答案 0 :(得分:5)
rvalue引用是程序员或编译器承诺所引用的数据即将被处理掉 1 ,并且读者以合理的方式更改它是可以接受的阅读速度更快(除其他外)。
如果您使用上述承诺从vector
数组中进行复制,则可以明确move
包含vector
s,以获得可能的巨大性能提升。
所以不,这不是缺陷。
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
}
在这种情况下,事情有点人为,但一般来说,数据来源可能是move
d。如果整个容器是move
d(右值参考),则rvalue覆盖会移动子数据,否则会复制。
通过更多的工作,我们可以编写上面的内容,以便一切都在一个方法中发生。因此,如果我们有一个rvalue容器(也就是拥有范围),并且容器本身不适合直接移动,我们move
内容。但这只是高级元编程,而不是答案所必需的。
1 编译器在限制情况下执行此操作,涉及在使用后“无法”引用的对象,因为它是匿名临时的,或者因为它在某些情况下在返回值中使用功能。 (实际上这不是不可能的,理论上这个C ++ 11特性可能会破坏前C ++ 11代码,但它非常接近)。程序员通过右值转换来执行此操作。它究竟意味着它将“立即处置”取决于上下文,但一般规则是rvalue引用的使用者可以将对象置于任何仍然可以被销毁和交互的“有效”状态。基于rvalue的swap
的存在意味着将其置于仅被销毁的状态是不安全的。
答案 1 :(得分:2)
r值参考是两件事:
在C ++中,通过引用传递数组允许,特别是确保它的长度,与C void func(int a[5])
相比已经是一个改进,其中传递长度为2的数组是完全可以接受的(虽然好的编译器将会警告)。
对数组的r值引用的好处不那么直接,但是:
restrict
一样因此,即使使用数组,也可以进行优化。
答案 2 :(得分:2)
你不能拥有阵列临时数据并不完全正确。你可以
void f(const std::string(&&x)[2]) {
std::cout << "rvalue" << std::endl;
}
void f(const std::string(&x)[2]) {
std::cout << "lvalue" << std::endl;
}
template<typename T>
using id = T;
int main() {
f(id<std::string[]>{"Hello", "Folks"});
f(id<std::string const[]>{"Hello", "Folks"});
std::string array[] = { "Hello", "Folks" };
std::string const arrayConst[] = { "Hello", "Folks" };
f(array);
f(arrayConst);
}
从C ++ 14开始,you are also allowed将支持的init列表直接传递给rvalue重载
f({ "Hello", "Folks" });
答案 3 :(得分:1)
它几乎不是缺陷,它引入了将对象移动到目标的令人兴奋的能力。这意味着目标句柄被交换为即将超出范围的源。