将成员函数指针与0进行比较总是有效的C ++吗?

时间:2011-01-12 05:48:25

标签: c++ function pointers member virtual-functions

在下面的代码中,使用Visual Studio编译器不会引发断言,但在使用XCode编译iPhone时会引发该断言:

class X
{
public:

 virtual void A() {}
};

X x;

void main()
{
 // Define a valid member function pointer to X::A.
 void (X::*p)() = &X::A;

 assert(p != 0);
}

这是编译器中的错误吗?在这种情况下,如何检查空指针呢?

2 个答案:

答案 0 :(得分:10)

代码是正确的,编译器不符合标准,使用C ++ 0x草案n3225中的措辞([expr.eq]部分),但在其他版本中它应该是相同的):

  

任何指向成员的指针都可以与空指针常量

进行比较

  

如果两个操作数均为空,则它们相等。否则,如果只有一个为null,则它们比较不相等。

空指针常量的相关定义([conv.ptr]部分,std::nullptr_t部分是C ++ 0x中的新部分):

  

空指针常量是整数类型的整数常量表达式(5.19)prvalue,其求值为零或类型为std::nullptr_t的prvalue。

和([expr.const]}部分:

  

如果常量表达式是整数或枚举类型,则它是一个整型常量表达式。

注意:另外,指向虚拟成员函数的指针的实现定义表示通常是虚拟表的索引,在问题中为0。但是根据标准,assert中的表达式不是检查表示是否为零,而是检查零文字 - 它是一个空指针检查。

Apple编译器显然混淆了两者。如果你想测试表示是否为零,你可以写assert((intptr_t)p != 0) - 这将是完全不可移植。

但是编写的代码非常易于移植到任何符合标准的编译器,并且永远不会断言

编辑:还有一个来自标准的引用,它重复了我们已经学过的内容([conv.mem]部分):

  

空指针常量(4.10)可以转换为指向成员类型的指针;结果是该类型的 null成员指针值,并且可以与任何不是从空指针常量创建的成员的指针区分开来。

答案 1 :(得分:3)

iPhone编译器弄错了。

请注意,指向虚函数的成员函数指针之间的等式比较会产生未指定的结果,即此断言

assert(&X::A == &X::A);
从正式的角度来看,

表现得无法预测。

但是成员函数指针与空指针常量的比较是由语言严格定义的。在您的示例中,指针不能为空,因此它不应该等于空指针常量。