【问题标题】:Is it always valid C++ to compare a member function pointer with 0?将成员函数指针与 0 进行比较总是有效的 C++ 吗?
【发布时间】:2011-01-12 05:48:25
【问题描述】:

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

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

【问题讨论】:

  • @Mahesh:我认为这不能回答他的问题。他并不是说assert 导致他的程序在为 iPhone 编译时终止。他在问为什么没有在 Visual Studio 下提出断言。
  • @Mahesh:问题不在于断言的行为,而在于被测试的表达式被编译器错误地评估了。 p != 0 必须根据标准评估为真。
  • main 永远不会返回 void,永远不会返回 int
  • @Merlyn: assert(true) 在调试和发布模式下都是无操作的。里面的表达式为真,由标准保证。

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


【解决方案1】:

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

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

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

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

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

和([expr.const] 部分):

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

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

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

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

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

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

【讨论】:

  • NULL 但是在 OPs 代码中或在标准的引用部分中没有出现——标准确实明确指出计算为零的整数常量(在 OP 的断言中使用)将被转换为空指针常量,这就是标准在这里所指的。不是预处理器宏 NULL。
  • @GMan:我知道这在每个编译器中都会有效地发生,但它实际上是在 NULL == 0 的 C++ 标准中定义的吗?
  • @Lambert:是的,这就是每个人都想告诉你的。我在编辑后的答案中引用了标准中的相关定义。
  • @Lambert:C 版本(例如((void*)0))在可变长度参数列表中的行为可能不同。但这不是可移植的,因为NULL 通常被简单地定义为0。许多 C++ 专家,包括 Stroustrup IIRC,只使用 0 并放弃 NULL 宏。
  • @Lambert:GMan 没有提到 C++0x。我做到了,而且我还特别告诉你 C++0x 在哪里改变了一些东西(新的std::nullptr_t 类型)。
【解决方案2】:

iPhone 编译器出错了。

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

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

从正式的角度来看,行为不可预测。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    • 2018-10-18
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多