我来自C#背景,正在努力学习一些C++。我遇到了以下线路:
int x[3] = { 1, 2, 3 };
int*&& y = x;
int* z = y;
我知道什么是指针和数组,对左值和右值引用也有一些了解。然而,我无法理解int*&& y = x;
的实际作用。它读起来就像创建了一个指向右值引用的指针,这是正确的吗?类似的东西的用例是什么,例如,如果我们执行这个,内存中会发生什么?
int*&& y = x;
将y
声明为指向int
的指针的右值引用,并使用x
对其进行初始化。(请注意,C++中不存在指向引用类型(例如int&&*
)的指针。)
现在的问题是x
是int
的数组,而不是指向int
。因此引用不能直接绑定到x
。类型与引用不兼容。
在这种情况下(如果引用是右值引用或const
左值引用),将创建引用类型的(未命名的)临时对象,而引用将绑定到该对象。在这种情况下,int*
对象被创建并用x
初始化,这通过数组到指针的衰减意味着int*
临时对象将被初始化为指向数组x
的第一个元素。
临时对象通常只生存到创建它们的(full-)表达式结束,但在这种情况下,因为引用立即绑定到它,所以应用所谓的临时生存期扩展,并且临时int*
对象将与引用一样长时间地生存(即,直到引用的作用域结束)。
换句话说,它(主要)相当于
int* /*unnamed*/ = x;
int*&& y = /*unnamed*/;
其中注释CCD_ 17被假定表示临时对象的不存在的名称。
当在表达式中使用引用的名称时(这完全独立于它是左值引用还是右值引用),它的行为与引用绑定到的对象的名称完全相同(但引用的类型去掉了引用限定符,例如可能相差const
)。
换句话说,CCD_ 19的行为等同于CCD_ 20。因此,z
是从临时int*
对象初始化的,该对象具有指向x
数组的第一个元素的指针值。对于像int*
这样的标量类型,初始化只是复制值,因此z
也将被初始化为指向x
的第一个元素。
整件事错综复杂。它与int* z = x;
完全等价。使用右值引用通常只有在函数参数和发生类型推导的一些构造中才有意义。左值和右值引用之间的重要区别在于,它们对重载解析的影响不同,并且可以使用不同的值类别对它们进行初始化。在类型推导中还有一种特殊情况,其中右值引用的行为不同(即所谓的转发引用)。除此之外,不同类型的参考文献之间没有区别。
如果我们执行这个,内存中会发生什么?
这主要是一个不重要的实现细节。您有一个数组,它存储在某个地方,这取决于您在程序中放置这些行的位置。如果编译器不认为不需要它,那么它很可能存在于内存中的某个物理位置。引用y
、它所指向的临时int*
和z
指针可能实际存在或可能不存在于某些存储器中,但编译器可能只是将它们全部直接减少到数组中。特别是,在语言级别上,引用不是对象,也没有存储(例如,它们没有内存大小或位置)。如果编译器需要一些内存来实现它们(例如作为指针),那么这纯粹是编译器的实现细节。