在下面的代码中,使用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);
}
这是编译器中的错误吗?在这种情况下,如何检查空指针呢?
答案 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);
从正式的角度来看,表现得无法预测。
但是成员函数指针与空指针常量的比较是由语言严格定义的。在您的示例中,指针不能为空,因此它不应该等于空指针常量。