都 (a)
并(b)
导致不确定的行为。通过空指针调用成员函数始终是未定义的行为。如果该函数是静态的,那么从技术上讲它也是未定义的,但是存在一些争议。
首先要了解的是为什么取消引用空指针是未定义的行为。在C ++ 03中,实际上这里有些歧义。
尽管“取消引用空指针会导致未定义的行为”在第1.9 / 4和8.3.2 / 4节中都提到了,但从未明确指出。(注释是非规范性的。)
但是,可以尝试从§3.10/ 2推论得出:
左值是指对象或函数。
取消引用时,结果为左值。空指针不会对象,因此,当我们使用左值时,我们具有未定义的行为。问题在于,前一句话从未声明过,所以“使用”左值是什么意思?只是生成它,还是在执行左值到右值转换的更正式意义上使用它?
无论如何,它绝对不能转换为右值(第4.1 / 1节):
如果左值所引用的对象不是类型T的对象,也不是从T派生的类型的对象,或者该对象未初始化,则需要进行此转换的程序将具有未定义的行为。
这绝对是未定义的行为。
不确定性来自于是否是不确定的行为,要遵循但不使用无效指针中的值(即获取左值,而不将其转换为右值)。如果没有,则int *i = 0; *i; &(*i);
定义明确。这是一个活跃的问题。
因此,我们有一个严格的“取消引用空指针,获得未定义的行为”视图和一个较弱的“使用取消引用的空指针,获得未定义的行为”视图。
现在我们考虑这个问题。
是的,(a)
导致未定义的行为。实际上,如果this
为null,则无论函数的内容如何,结果都是不确定的。
这是从第5.2.5 / 3节得出的:
如果E1
类型为“指向类X的指针”,则表达式E1->E2
将转换为等效形式(*(E1)).E2;
*(E1)
严格解释会导致不确定的行为,并且 .E2
并将其转换为右值,从而使弱解释的行为不确定。
它也遵循直接来自(§9.3.1/ 1)的未定义行为:
如果为非X类型或非X类型派生的对象调用类X的非静态成员函数,则该行为是不确定的。
对于静态函数,严格和弱解释会有所不同。严格来说,它是未定义的:
可以使用类成员访问语法引用静态成员,在这种情况下,将评估对象表达式。
也就是说,它的评估就像是非静态的一样,我们再次使用取消引用空指针(*(E1)).E2
。
但是,由于E1
未在静态成员函数调用中使用,因此如果使用弱解释,则该调用是明确定义的。*(E1)
产生左值,静态函数被解析,*(E1)
被丢弃并调用该函数。没有从左值到右值的转换,因此没有未定义的行为。
从n3126开始,在C ++ 0x中,歧义仍然存在。现在,请放心:使用严格的解释。