推迟返回的参考

Deferencing a returned reference

本文关键字:参考 返回 推迟      更新时间:2023-10-16

给定:

int& foo(); // don't care what the reference is to
int intVal;

在以下两种情况下,右侧是相同的函数调用

int& intRef = foo();
intVal = foo();  // a reference is returned... a value is assigned.

在第二种情况下,返回的引用如何"转换"到值?

是由分配运营商完成的INT?

在语言层面上,没有诸如"退出参考"之类的概念。引用实现了 lvalue 的概念。变量和参考基本上是同一件事。变量和参考之间的唯一区别是,该变量是由编译器自动绑定到存储中的位置,而通常在运行时通过用户操作绑定了参考。

在您的示例中,intRefintVal之间没有概念上的差异。两者都是int型的lvalues。在概念层面上,两者都是通过相同的机制访问的。您甚至可以将程序中的所有变量视为参考文献,这些变量是由编译器隐含的。这基本上是Bjarne Stroustrup在TC PL中的含义(而不是逐字化),人们可以将参考视为现有变量的替代名称。

唯一可感知两者之间的差异的时刻是创建这些实体并初始化它们。参考的初始化是将其绑定到存储中某些位置的行为。变量的初始化是将初始值复制到现有存储中的行为。

但是,一旦初始化了参考,它就可以作为普通变量:读取/写作的行为是读取/编写其绑定的存储位置的行为。将参考评估的地址评估到其绑定的存储位置的地址。等等。

在许多情况下,在内部将参考作为伪装的指针实现,即作为无形指针,每次访问它时都会为您隐含地使用它。在这种情况下(当它通过指针真正实现时),每次您访问它时,都会再次进行解释。因此,正如您在问题中提出的那样,不是任务操作员。您在代码中提到该参考的名称的事实是,导致无形指针被删除。

但是,实现"现有变量的替代名称"的实体并不一定需要存储自身,即用汇编的语言,不需要任何材料代表的东西,例如隐藏的指针。这就是为什么8.3.2中语言标准指出"未指定是否需要存储的情况"。

foo正在返回一些引用类型" int"的对象。我们不在乎" int"的来源,我们只是假设它存在。

第一行int& intRef = foo()创建intRef,它也指类型" int"的对象与foo的返回值。

所引用的对象。

第二行,intVal的值被返回的参考所指的对象的值代替。


回应您的评论:

您似乎对指针和参考文献感到非常困惑。引用就像一个对象的别名。对参考进行任何操作实际上会影响其指的对象。

没有提起参考的东西。您只能取消指针。提出的行为是使用Unary *操作员将对象指向一个点。例如,如果您有int* p,则可以执行*p以获取指向的对象。这是 dereferencing p

您唯一可以在引用上执行*的时间是它指的是指针(或者它过载operator*)。在您的情况下,由于foo返回int&,因此我们无法将其解释。表达式*foo()只是不会编译。这是因为foo的返回值具有" INT"类型,这不是指针,也不超载operator*

出于所有意图和目的,您可以将从foo返回的参考视为它所指的对象。将此值分配给intVal确实与在以下代码中为intVal分配x并没有什么不同:

int intVal;
int x = 5;
intVal = x;

我确定您了解,intVal被赋予x的值。这仅由标准来定义:

在简单分配(=)中,表达式的值替换了左操作数所指对象的值。

根本不需要转换,因为操作员的两侧都是相同的类型。

这与您的情况确实没有什么不同。您只有:

intVal = some_ref_to_int;

其中some_ref_to_int是表达式foo()。这是参考的事实并不重要。intVal接收参考表示的对象的值。

分配给 intVal是标准中5.17 [exp.ass]中定义的 sigsment-expression 。根据其他几个语法规则,分配表达的语法规则非常复杂,但基本上您需要在=操作员的左侧进行修改的LVALUE,右边的Prvalue表达式手部。

的情况下
intVal = foo();

RHS上的表达式是类型int的lvalue,因此内置的lvalue-to-rvalue转换发生了...这几乎不是转换,因为该值不会改变,并且类型也不会改变(除了删除基本类型的基本类型,因此,如果LVALUE是型号const int,则Prvalue将为int类型)。[cons.lval]说

非功能,非阵列类型T的glvalue(3.10)可以转换为prvalue。[...]如果T是一种非类型类型,则PRVALUE的类型是T的CV UNQUALIFIED版本。否则,Prvalue的类型为T。[...] glvalue指示的对象中包含的值是prvalue结果。

因此,prvalue具有类型的int,并且与foo()相同的值,即与返回的引用绑定到的变量相同的值。

分配表达式的规则说:

在简单分配(=)中,表达式的值替换了左操作数所指的对象的值。

因此,intVal的值将被Prvalue的值所取代。规则继续:

如果左操作数不是类型,则该表达式被隐式转换为左操作数的CV UNQUALIFIED类型。

因此,由于int不是类类型(因此没有过载的operator=,因此仅使用内置分配运算符),分配将将RHS转换为int,这是您的情况下已经具有的类型。p>因此, intVal的值设置为prvalue的值,我们说这是glvalue表达式 foo()的值,即变量的值,引用绑定到。

请注意,LVALUE-RED-REGRAUE转换与RHS是参考无关。同样的事情在这里发生:

int val = 0;
intVal = val;

val是类型int的LVALUE,因此将其转换为int类型的Prvalue,intVal的值设置为该prvalue的值。

规则是用表达式的"值类别"(即lvalue或rvalue)表示的,而不是是否是参考。所需的参考文献的任何"删除"都是由编译器隐式和不可见的,以实施所需的行为。