是否在NULL指针上调用函数未定义?

时间:2012-02-28 20:57:06

标签: c++ undefined-behavior

  

可能重复:
  When does invoking a member function on a null instance result in undefined behavior?
  C++ standard: dereferencing NULL pointer to get a reference?

说我有班级:

class A
{
public:
   void foo() { cout << "foo"; }
};

并像这样调用foo:

A* a = NULL;
a->foo();

我怀疑这会调用未定义的行为,因为它等同于(*a).foo()(或者它是?),取消引用NULL UB,但我找不到参考资料。谁能帮我吗?还是定义了?

不,该功能不是virtual。不,我没有访问任何成员。

编辑:我投票决定关闭这个问题,但不会删除它,因为我自己找不到副本,我怀疑其他人可能更容易找到这个标题。

4 个答案:

答案 0 :(得分:9)

  

我正在寻找a->x相当于(*a).x的参考文献。

这是:

  

[C++11: 5.2.5/2]:对于第一个选项(点),第一个表达式应具有完整的类类型。对于第二个选项(箭头),第一个表达式应具有指向完整类类型的指针。 表达式E1->E2转换为等效形式(*(E1)).E2; 5.2.5的剩余部分将仅解决第一个选项(点)。在任何一种情况下, id-expression 都应该命名该类或其一个基类的成员。 [注意:因为类的名称是在其类作用域中插入的(第9节),所以类的名称也被视为该类的嵌套成员。 -end note ] [注意: 3.4.5描述了如何在.->运算符后查找名称。 -end note ]

遗憾的是,没有直接引用解除引用NULL指针为UB。您可以在此问题下找到更多内容:When does invoking a member function on a null instance result in undefined behavior?

答案 1 :(得分:1)

我知道至少有一种情况,这个习惯用法不仅允许而且依赖:Microsoft的MFC类CWnd提供了一个成员函数GetSafeHwnd,它测试this==NULL是否返回而不访问任何成员变量。

当然,有很多人会声称MFC是一个非常糟糕的例子。

无论行为是否未定义,实际上行为都不太可能。只要a->foo()不是虚拟的,编译器就会将A::foo(a)视为foo,而{{1}}不会在呼叫站点进行解除引用。

答案 2 :(得分:0)

是的,这是UB,因为a尚未初始化为指向有效的内存位置,然后才会取消引用。

答案 3 :(得分:0)

此处介绍:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232

  

IS中至少有几个地方表示间接通过   null指针产生未定义的行为:1.9 [intro.execution]   第4段给出了“取消引用空指针”作为例子   未定义的行为,以及8.3.2 [dcl.ref]第4段(在注释中)使用   这种被认为是未定义的行为作为理由   不存在“空引用”。

     

然而,5.3.1 [expr.unary.op]第1段,其中描述了一元   “*”运算符,并不表示如果行为是未定义的   人们可能期望操作数是一个空指针。此外,至少   一个段落提供解除引用空指针明确定义的行为:   5.2.8 [expr.typeid]第2段说

     

如果通过应用一元*运算符获得左值表达式   到一个指针,指针是一个空指针值(4.10   [conv.ptr]),typeid表达式抛出bad_typeid异常   (18.7.3 [bad.typeid])。

     

这是不一致的,应该清理。

如果您想了解更多信息,请在链接中阅读更多内容。