9

我正在阅读 C++ 常见问题解答 - “ 8.6 - 何时应使用引用,何时应使用指针? ”,尤其是以下语句:

尽可能使用引用,必要时使用指针。

...

上述情况的例外是函数的参数或返回值需要一个“哨兵”引用——一个不引用对象的引用。这通常最好通过返回/获取一个指针,并赋予 NULL 指针特殊的意义(引用必须始终为对象别名,而不是取消引用的 NULL 指针)。

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

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

编辑:

我不确定我的问题是否清楚——我想我并没有乱七八糟地询问 NULL 引用。大多数情况下,我在 C++ 中读到“引用就是对象”。而且,在大多数 OOP 语言中,对象可以是 NULL - Pascal、C#、Java、JavaScript、PHP 等,您可以在所有这些中执行someObject = nullsomeObject := nil. 事实上,Pascal 也支持指针,但仍然允许对象是nil,因为它有它的用途。那么为什么 C++ 有某种特殊性并且没有 NULL 对象呢?这只是一个疏忽还是一个实际的决定?

4

5 回答 5

14

因为引用带有指向一个永不改变的有效内存地址的语义;即取消引用它是安全/定义的,因此不需要 NULL 检查。不能通过设计重新分配参考。

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

使用指针的一个示例是作为类的成员来存储对某个实例的“引用”,该实例在类构造时可能不知道或无法初始化。但是,成员引用必须在构造时初始化(通过初始化列表),并且不能推迟它们的分配。

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

更新:

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

我想你对此有点困惑。Java 和 C# 等可能会给人一种“NULL 对象”的印象,但这些对象引用或多或少像一个 C++ 指针,具有更简单的语法、GC 检测和异常抛出。在这些语言中,如果您对“空对象”进行操作,您将得到某种异常,例如NullReferenceException (C#)。地狱,在 Java 中它被称为NullPointerException

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

C++ 观点是关于有选择的,因此是冗长的:

  • 使用普通指针随心所欲,必要时检查 NULL。
  • 使用具有编译器强制有效性语义/约束的引用。
  • 滚动您自己的智能指针,这些指针可以记账并按照您希望的方式运行。
  • 如果需要,使用 void 指针(小心!)来引用无类型的内存块。
于 2012-07-10T07:55:41.057 回答
6

请看一下指针和引用之间的区别——虽然标准让引用的实现方式保持开放,但它们目前总是作为指针实现。

这意味着它们之间的主要区别是 a) 语义 b) 指针可以重新定位 c) 指针可以为空。

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

标准是否允许空引用,您总是必须在使用引用之前检查空值,这是不想要的。

编辑:

关于您的编辑,我想这里的混淆可能源于大多数简单的面向对象语言隐藏正在发生的事情这一事实。以 Java 为例,虽然看起来你有 NULL 对象,并且可以分配它们,但你真的不能 - 真正发生的是 Java 只有指针,并且可以为这些指针分配空值。由于在 Java 中实际上不可能直接拥有对象,因此它们取消了指针语义并将指针视为对象。C++ 更强大 - 并且容易出错(Java 爱好者会说堆栈用户类实例不是必需的,并且在 Java 中不使用它们的决定是为了降低复杂性,并使 Java 更易于使用)。这也随之而来,因为 Java 没有对象,所以它没有引用。然而,真正没有帮助的是,

于 2012-07-10T07:58:48.837 回答
1

定义引用应该与另一个变量或对象相关联。因此,空引用或空引用违反了它的存在目的。

从技术上讲,这意味着您从空引用开始,然后将其分配给某个变量,或者可能稍后重新分配给另一个变量。这根本不是要创建的参考。

引用不能复制的指针还有其他几种用途。例如,使用指针引用具有少量内存的大量复杂数据(字节序列),并通过仅花费 8 个字节左右的指针来根据需要频繁地传递它。您不能在不浪费相同内存的情况下通过引用来做到这一点。

引用总是与类型相关联,而指针则不是这种情况。

于 2012-07-10T07:58:03.007 回答
1

C++ 引用不是大多数其他语言使用该术语的意义上的引用。它更像是一个别名。使用 C++ 引用并不涉及以与取消引用指针相同的方式“取消引用”它;它实际上分配给它的对象。

没有真正的空对象实例这样的东西,所以你不能创建对这样的东西的 C++ 引用。在其他语言中,空引用等同于 C++ 空指针。它实际上不包含任何内容。

现在,关于您的其他想法: 1. 拥有不可为空的引用对我来说是件好事;这意味着您可以获得通过引用传递的所有好处,而无需在所有地方检查空值。2. 可空引用不能代替指针...如果您需要在低级别进行内存或 IO 工作,您将需要对内存和内存映射设备的原始访问。您可以查看 C#(或 C++/CLR),正是出于这个原因,它具有托管引用和非托管指针。

于 2012-07-10T10:14:32.477 回答
0

引用必须引用某些东西,因此,空引用不可用。
C 没有引用,在这种语言中我们只能使用指针,因此,这是与 C 语言的兼容性

于 2012-07-10T07:55:26.200 回答