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

Kov*_*vsa 3 c++ pointers virtual-functions function member

在下面的代码中,使用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);
}
Run Code Online (Sandbox Code Playgroud)

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

Ben*_*igt 10

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

任何指向成员的指针都可以与空指针常量进行比较

和

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

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

甲空指针常数是整数表达式(5.19),用于评估至零或类型的prvalue整数类型的prvalue std::nullptr_t.

和(部分[expr.const]):

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

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

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

但是编写的代码对任何符合标准的编译器都是完全可移植的,并且永远不会断言.

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

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

  • 虽然在OPs代码中没有出现NULL,或者在标准的引用部分中 - 标准明确声明了一个求值为零的整数常量(在OP的断言中使用)将被转换为空指针常量,这就是标准所指的内容.不是预处理器宏NULL. (2认同)