C++ 推迟返回的引用

C++ 推迟返回的引用,c++,reference,C++,Reference,鉴于: 在以下两种情况下,右侧是相同的函数调用 int& foo(); // don't care what the reference is to int intVal; 在第二种情况下,返回的引用如何“转换”为值 它是由int的赋值运算符完成的吗?在语言级别,没有“取消引用”这样的概念。引用实现了左值的概念。变量和引用基本上是一样的。变量和引用之间的唯一区别在于,编译器会自动将变量绑定到其在存储器中的位置,而引用通常是在运行时通过用户操作绑定的 在您的示例中,intRef和intV

鉴于:

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

int& foo(); // don't care what the reference is to
int intVal;
在第二种情况下,返回的引用如何“转换”为值


它是由int的赋值运算符完成的吗?

在语言级别,没有“取消引用”这样的概念。引用实现了左值的概念。变量和引用基本上是一样的。变量和引用之间的唯一区别在于,编译器会自动将变量绑定到其在存储器中的位置,而引用通常是在运行时通过用户操作绑定的

在您的示例中,
intRef
intVal
之间没有概念上的区别。两者都是
int
类型的左值。在概念层面,两者都是通过相同的机制实现的。您甚至可以将程序中的所有变量都视为引用,编译器会隐式地为您预先绑定这些变量。这基本上就是Bjarne Stroustrup在TC++PL中的意思,他说(不是逐字)可以将引用看作是现有变量的替代名称

只有当您创建并初始化这些实体时,才能感觉到两者之间的差异。引用的初始化是将其绑定到存储中某个位置的行为。变量初始化是将初始值复制到现有存储器中的操作

但一旦引用被初始化,它就充当普通变量:读/写引用的行为就是读/写它绑定到的存储位置的行为。获取引用的地址将计算为它绑定到的存储位置的地址。等等

在许多情况下,引用在内部实现为伪装的指针,也就是说,作为一个不可见的指针,每次访问时都会隐式取消引用,这并不是秘密。在这种情况下(当它真正通过指针实现时),每次访问它时,都会再次执行解引用。所以,正如你在问题中所问的,不是赋值操作符做的。正是由于您在代码中提到了该引用的名称,才导致不可见指针被取消引用


然而,实现“现有变量的替代名称”的实体本身不一定需要存储,也就是说,在编译语言中,它不需要由任何材料表示,如隐藏指针。这就是为什么语言标准在8.3.2中规定“未指定引用是否需要存储”。

foo
返回对“int”类型对象的一些引用。我们不关心“int”来自哪里,我们只会假设它存在

第一行,
int&intRef=foo()


第二行,
intVal
的值被返回的引用所引用的对象的值替换


针对你的评论:

您似乎对指针和引用感到非常困惑。引用就像对象的别名一样。对引用执行任何操作实际上都会影响它所引用的对象

没有解引用这样的事情。只能取消引用指针。解引用是使用一元
*
运算符获取点指向的对象的行为。例如,如果您有一个
int*p
,您可以执行
*p
来获取它所指向的对象。这是解引用
p

对引用执行
*
操作的唯一时间是它所引用的对象是否是指针(或者如果它重载了
运算符*
)。在您的情况下,由于
foo
返回一个
int&
,因此我们不能取消对它的引用。表达式
*foo()
无法编译。这是因为
foo
的返回值具有类型“int”,它不是指针,并且不会重载
运算符*

出于所有目的,您可以将从
foo
返回的引用视为它引用的对象。将此值指定给
intVal
实际上与在以下代码中将
x
指定给
intVal
没有什么不同:

int& intRef = foo();
intVal = foo();  // a reference is returned... a value is assigned.
我相信您会理解,
intVal
的值为
x
。这仅由标准定义:

在简单赋值(
=
)中,表达式的值替换左操作数引用的对象的值

根本不需要进行转换,因为运算符的两侧都是相同的类型

这与你的情况没有什么不同。你只需要:

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

其中
some\u ref\u to\u int
是表达式
foo()
。事实上,这是一个参考并不重要
intVal
接收引用所表示对象的值。

赋值给
intVal
是本标准5.17[exp.ass]中定义的赋值表达式。赋值表达式的语法规则相当复杂,这取决于其他几个语法规则,但基本上,在
=
运算符的左侧需要一个可修改的左值,在右侧需要一个prvalue表达式

intVal = some_ref_to_int;
RHS上的表达式是类型为
int
的左值,因此会发生内置左值到右值的转换。。。这仅仅是一种转换,因为值不会改变,类型也不会改变(除了基本类型的cv限定符被删除,因此如果左值是type
const int
,prvalue将是type
int
)。[conv.lval]说

非函数、非数组类型的glvalue(3.10)
T
can b
intVal = foo();
int val = 0;
intVal = val;