答案取决于您的观点:
如果根据C ++标准进行判断,则无法获取空引用,因为您首先会获得未定义的行为。在第一次出现不确定行为之后,该标准允许发生任何事情。因此,如果您编写*(int*)0
,那么从语言标准的角度来看,您已经具有未定义的行为,即取消引用空指针。程序的其余部分无关紧要,一旦执行了此表达式,您就退出了游戏。
但是,实际上,可以很容易地从空指针创建空引用,直到您真正尝试访问空引用后面的值时,您才会注意到。您的示例可能有点太简单了,因为任何好的优化编译器都会看到未定义的行为,并简单地优化掉所有依赖于它的内容(甚至不会创建null引用,它也会被优化掉)。
但是,优化工作取决于编译器来证明未定义的行为,这可能是不可能做到的。考虑一下文件内的这个简单函数converter.cpp
:
int& toReference(int* pointer) {
return *pointer;
}
当编译器看到此函数时,它不知道指针是否为空指针。因此,它只是生成将任何指针转换为相应引用的代码。(顺便说一句,这是一个小问题,因为指针和引用在汇编程序中是完全相同的野兽。)现在,如果您还有另一个user.cpp
包含代码的文件
#include "converter.h"
void foo() {
int& nullRef = toReference(nullptr);
cout << nullRef; //crash happens here
}
编译器不知道 toReference()
将取消对传递的指针的引用,并假定它返回有效的引用,实际上,该引用将为空引用。调用成功,但是当您尝试使用引用时,程序崩溃。希望。该标准允许发生任何事情,包括出现粉红色大象。
您可能会问为什么这是相关的,毕竟,内部已经触发了未定义的行为toReference()
。答案是调试:空引用可能像空指针一样传播和扩散。如果您不知道可以存在空引用,并学会避免创建空引用,则可能要花费大量时间来弄清楚为什么成员函数在尝试读取普通旧int
成员时似乎崩溃了(答案:实例在该成员的调用中,有一个空引用,this
一个空指针也是如此,并且您的成员被计算为位于地址8)。
那么如何检查空引用呢?你给了电话
if( & nullReference == 0 ) // null reference
在你的问题。嗯,那是行不通的:按照标准,如果取消引用空指针,您将具有未定义的行为,并且不能不引用空指针而创建空引用,因此,空引用仅存在于未定义行为的领域内。由于编译器可能假定您未触发未定义的行为,因此可以假定不存在空引用(即使它很容易发出生成空引用的代码!)。这样,它看到了if()
条件,得出结论说它不能成立,只是丢弃了整个if()
语句。随着链接时间优化的引入,以健壮的方式检查空引用已变得毫无可能。
TL; DR:
空引用有些可怕地存在:
它们的存在似乎是不可能的(按标准而言),
但是它们存在(按生成的机器代码来确定),
但是您看不到它们是否存在(=您的尝试将被优化),
但是无论如何它们可能会杀死您(=您的程序在怪异的点崩溃甚至更糟)。
您唯一的希望是它们不存在(=编写您的程序以不创建它们)。
我希望那不会困扰您!