它是否始终有效 C++将成员函数指针与 0 进行比较?

发布于 2024-10-11 13:21:11 字数 297 浏览 6 评论 0原文

在以下代码中,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);
}

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

In the following code, the assertion is not raised with the Visual Studio compiler, but it is raised when compiling for the iPhone using XCode:

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);
}

Is this a bug in the compiler? How else can one check for a null pointer in this case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

独﹏钓一江月 2024-10-18 13:21:11

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

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

,并且

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

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

空指针常量是整数类型的整型常量表达式 (5.19) 纯右值,其计算结果为零或 std::nullptr_t 类型的纯右值。

和([expr.const] 部分):

如果常量表达式是整型或枚举类型,则该常量表达式是整型常量表达式。

注意:顺便说一句,指向虚拟成员函数的指针的实现定义表示通常是虚拟表的索引,在问题中为 0。但根据标准,断言内的表达式并不检查表示形式是否为零,而是检查零文字 - 这是空指针检查。

苹果编译器显然将两者混为一谈。如果您想测试表示形式是否为零,您可以编写 assert((intptr_t)p != 0) ——这将是完全不可移植的。

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

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

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

The code is correct, the compiler is out of compliance with the standard, which says (section [expr.eq], using the wording from C++0x draft n3225, but it should be the same in other versions):

any pointer to member can be compared to a null pointer constant

and

If both operands are null, they compare equal. Otherwise if only one is null, they compare unequal.

relevant definition of null pointer constant (section [conv.ptr], the std::nullptr_t part is new in C++0x):

A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to zero or a prvalue of type std::nullptr_t.

and (section [expr.const]):

A constant expression is an integral constant expression if it is of integral or enumeration type.

NOTE: As an aside, the implementation-defined representation of pointer-to-virtual-member-function usually is an index into the virtual table, which would be 0 in the question. But according to the standard, the expression inside the assert isn't checking if the representation is zero, it's checking against a zero literal -- it is a null pointer check.

And the Apple compiler apparently mixed the two up. If you wanted to test if the representation is zero, you could write assert((intptr_t)p != 0) -- and that would be completely non-portable.

But the code as written is perfectly portable, to any standard-compliant compiler, and will never assert.

EDIT: And one more citation from the standard, which just repeats what we've already learned (section [conv.mem]):

A null pointer constant (4.10) can be converted to a pointer to member type; the result is the null member pointer value of that type and is distinguishable from any pointer to member not created from a null pointer constant.

过气美图社 2024-10-18 13:21:11

iPhone 编译器出错了。

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

assert(&X::A == &X::A);

从形式的角度来看,此断言的行为是不可预测的。

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

The iPhone compiler gets it wrong.

Note that equality comparison between member function pointers that point to virtual functions produces unspecified result, i.e. this assertion

assert(&X::A == &X::A);

behaves unpredictably from the formal point of view.

But comparison of a member function pointers with null-pointer constant is strictly defined by the language. The pointer cannot be null in your example, so it shall not compare equal to a null-pointer constant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文