【问题标题】:C++ standard: dereferencing NULL pointer to get a reference? [duplicate]C++ 标准:取消引用 NULL 指针以获取引用? [复制]
【发布时间】:2011-02-13 05:52:41
【问题描述】:

我想知道 C++ 标准对这样的代码是怎么说的:

int* ptr = NULL;
int& ref = *ptr;
int* ptr2 = &ref;

实际上,结果是 ptr2 为 NULL,但我想知道,这只是一个实现细节还是在标准中定义得很好?
在不同的情况下,NULL 指针的取消引用应该会导致崩溃,但在这里我取消引用它是为了获得一个由编译器作为指针实现的引用,因此实际上没有 NULL 的实际取消引用。

【问题讨论】:

标签: c++ pointers reference null


【解决方案1】:

取消引用 NULL 指针是未定义的行为。

事实上,标准在注释(8.3.2/4“参考”)中指出了这种确切的情况:

注意:特别是,空引用不能存在于定义良好的程序中,因为唯一的 创建此类引用的方法是将其绑定到通过取消引用空指针获得的“对象”,这会导致未定义的行为。


顺便说一句:有一次我知道 NULL 指针可以以明确定义的方式“取消引用”作为 sizeof 运算符的操作数,因为 sizeof 的操作数不是t 实际评估(因此取消引用实际上从未发生)。

【讨论】:

  • 事实上,如果它是typeid 的操作数,并且如果它是PolymorphClass* 类型的空指针,那么它会被取消引用求值。仍然定义明确(抛出bad_typeid)。我真的不喜欢那种特别的typeid 待遇。
  • 很遗憾不允许 NULL 引用。它展示了一些很酷的特性,但我想它只会使代码复杂化。 :( 如果前提条件可用并且可以更好地验证代码,则可以安全地使用 NULL 引用。
  • sizeof() 是变量类型的运算符,而不是值。 NULL 指针确实有类型。
  • @jforberg:我没有看到这里有人声称不是吗?
  • @Lightness 没有人是。我只是澄清一下。
【解决方案2】:

取消引用 NULL 指针是 C++ 标准中明确未定义的行为,因此您看到的是特定于实现的。

从 C++0x 草案标准中的 1.9.4 复制而来(这方面与以前的标准类似):

描述了某些其他操作 在本国际标准中为 未定义(例如,效果 取消引用空指针)。 [:本国际标准 没有要求 包含程序的行为 未定义的行为。 - 尾注]

【讨论】:

  • 这很有趣,因为没有人能够显示在标准取消引用空指针的哪个位置显式地进行了 UB。这里的标准不正确。
  • @curiousguy:8.3.2.5 再次暗示取消引用空指针是未定义的事实。但你是对的,它这样做就好像在别处解释过一样。无论如何,1.3.13 解释了任何未明确定义的行为都被认为是未定义的,因此可能是这种情况。
  • "8.3.2.5" 顺便说一句,它的拼写是 8.3.2/5。没有 8.3.2.5 部分。 “任何没有明确定义的行为都被认为是未定义的”你是对的:只有当指针指向一个对象时才定义解引用指针。但是,如果标准对此有明确的规定,那就更清楚了——并且在这个非问题上花费更少的电子墨水。
  • 注释是非规范性的。由于DR 1102 的原因,该注释实际上已被删除,其理由是取消引用空指针不是未定义的行为。
【解决方案3】:

取消引用 NULL 指针是未定义的行为。您应该在取消引用之前检查一个值是否为 NULL。

【讨论】:

    【解决方案4】:

    为了完整起见,http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 专门讨论了这个问题。

    【讨论】:

    • 嗯...很有创意的想法。因此,允许使用 null this 调用成员函数!!!我想知道他们在抽什么烟。无论如何,7 年后,在这种疯狂的方向上没有做任何事情。
    • 其实不是,根据stackoverflow.com/a/2474021/399317(因为左值到右值的转换)
    • 有趣的是,#232 使用除以零作为 UB 的示例,当许多 C++ 实现隐含地包含 IEEE-754 时,它定义了除以正零和负零的效果。 整数除以零是UB,但示例没有指定。
    • 你必须使用“许多”这个词是UB的一个例子。
    【解决方案5】:
    int& ref = *ptr;
    

    上面的语句实际上并没有取消引用任何东西。所以在你使用ref之前没有问题(这是无效的)。

    【讨论】:

    • 废话。一元 * 实际上是解引用运算符。它实际上执行解引用操作。
    • @curiousguy:我建议你编译这个并在反汇编器中查看代码。引用ref本质上是一个指针,所以上面的语句只是幕后的指针赋值。
    • 你误会我了。我不在乎生成了什么汇编代码。你说*ptr是什么?
    • @curiousguy: *ptr 确实是一种取消引用。但这并不意味着它实际上已经完成(评估)。例如,您可以编写 sizeof(*ptr) 并且表达式 *ptr 保证不会在运行时进行评估。
    • 确实,sizeof 的操作数没有被计算:你可以写sizeof(1./0.) 没有任何问题。那是因为sizeof 只关心其操作数的类型。 OTOH,& 的操作数被求值,否则 address-of 适用于什么?
    猜你喜欢
    • 1970-01-01
    • 2017-04-17
    • 2019-05-20
    • 1970-01-01
    • 1970-01-01
    • 2020-03-17
    • 2011-06-17
    • 2011-03-27
    相关资源
    最近更新 更多