为什么C++中没有"NULL引用"?

lau*_*ent 8 c++ null pointers specifications reference

我正在阅读C++ FAQ - " 8.6 - 我何时应该使用引用,何时应该使用指针? "特别是这句话:

尽可能使用引用,并在必要时使用指针.

...

上面的例外是函数的参数或返回值需要"sentinel"引用 - 一个不引用对象的引用.这通常最好通过返回/获取指针,并赋予NULL指针这一特殊意义(引用必须始终为别名对象,而不是取消引用的NULL指针).

从我所看到的,对"哨兵"引用的需求确实经常是使用指针而不是引用的原因.我想知道的是:为什么C++没有特殊的"NULL值"用于引用?它似乎会使指针几乎不必要,这将解决许多问题.

那么为什么它不是语言规范的一部分呢?

编辑:

我不确定我的问题是否清楚 - 我想我不是故意要求NULL引用.我经常在C++中读到"引用是对象".而且,在大多数OOP语言中,对象可以是NULL -帕斯卡尔,C#,Java和JavaScript的,PHP等,所有这些,你可以做someObject = nullsomeObject := nil.事实上,Pascal也支持指针,但仍然允许对象nil,因为它有它的用途.那么为什么C++在某种程度上是特殊的并且没有NULL对象呢?这只是一个忽视还是一个实际的决定?

Pre*_*eti 13

因为引用带有它指向永远不会改变的有效内存地址的语义; 即解除引用它是安全/定义的,因此不需要进行NULL检查.参考不能通过设计重新分配.

当var可以为NULL并且客户端代码必须处理该情况时,您使用指针.如果可以保证有效/初始化的内存地址,则使用引用.

使用指针的一个示例是作为类的成员,用于存储某些实例的"引用",这些实例可能在类构造时未知或无法初始化.但是,成员引用必须在构建时初始化(通过初始化列表),并且不能推迟其分配.

如果允许空引用,那么除了语法之外,它与指针没有区别(需要进行相同的NULL检查.)

更新:

"而且,在大多数OOP语言中,对象可以是NULL - Pascal,C#,Java,JavaScript,PHP等等.[...]那么为什么C++有些特殊并且没有NULL对象呢?它只是一个忽视还是一个实际的决定呢?"

我觉得你对此有点困惑.Java和C#等可能会给人一种"NULL对象"的印象,但这些对象引用或多或少类似于C++指针,具有更简单的语法,GC检测和异常抛出.在这些语言中,如果您使用"Null对象",您将获得某种异常,如NullReferenceException(C#).地狱,在Java中它被称为NullPointerException.

您必须先检查,null然后才能安全使用它们.有点像C++指针(除了在大多数托管语言中,默认情况下指针初始化为NULL,而在C++中,它通常取决于您设置初始指针值(否则未定义/已存在的任何内存)).

C++视图是关于选择的,因此是冗长的:

  • 使用普通指针做你喜欢的事,在必要时检查NULL.
  • 使用具有编译器强制有效语义/约束的引用.
  • 滚动自己的智能指针进行簿记,并按照您希望的方式运行.
  • 如果需要,使用void指针(小心!)引用无类型的内存块.

  • Nit:一个空指针和一个未初始化的指针是两个不同的东西.无法检测到未初始化的指针,至少不可靠,因为它可以指向任何位置,包括指向有效对象. (2认同)

Coo*_*kie 6

请看一下指针和引用之间的区别 - 虽然标准让它打开了如何实现引用,但它们目前始终是作为指针实现的.

这意味着它们之间的主要区别是a)语义b)指针可以重新安装c)指针可以为null.

所以简短的回答是,这是故意的.当您作为程序员看到引用时,您应该知道a)该引用已填充b)它不会更改(和c)您可以使用与对象相同的语义).

如果标准允许空引用,则在使用引用之前总是必须检查null,这是不需要的.

编辑:

关于你的编辑,我想这里的混乱可能源于这样一个事实,即大多数更简单的OO语言隐藏了正在发生的事情.以Java为例,虽然看起来你有NULL对象,并且可以分配它们,但你真的不能 - 真正发生的是Java只有指针,并且可以为这些指针分配空值.由于不可能直接在Java中实现对象,因此它们取消了指针语义并将指针视为对象.C++功能更强大 - 容易出错(Java爱好者会说不需要堆栈用户类实例,并且决定不在Java中使用它们来降低复杂性,并使Java更易于使用).由此可见,由于Java没有对象,因此它没有引用.但是,实际上没有帮助的是Java调用C++人称为指针传递值的传递方式.

  • 我不知道有很多OO语言,但对于我所做的那些我不同意.Java甚至没有引用,Java只有指针(例如可以为null,可以重新设置),尽管语法不同.Java没有引用的原因之一是因为Java也没有堆栈变量(缺少内置类型) - 一切都是堆,每个变量都是一个指针,因此可以为null,没有堆栈内存,不需要引用.vba也是如此.这和我所知道的OO语言差不多. (3认同)
  • 考虑例如C++中引用的典型用例:您有一些大的堆栈分配变量,并希望通过引用而不是值传递它们.在这里,您需要使用真正的C++引用,并且这样做是正确的,因为它们必须为非null且不会更改.在Java中,您不能拥有堆栈变量,因此调用环境始终只有指针,因此您不需要构造来通过引用传递.经常会出现混淆 - Java人称之为"通过引用传递"C++人员应该称之为"通过指针传递". (2认同)