是否合法/定义良好的C ++来调用不通过空指针访问成员的非静态方法?

时间:2010-07-15 15:55:34

标签: c++ pointers null methods standards

我最近遇到了以下代码:

class Foo
{
public:
    void bar();
    // .. other stuff
};

void Foo::bar()
{
    if(!this) {
        // .. do some stuff without accessing any data members
        return;
    }

    // .. do normal actions using data members
}

代码编译因为在C ++方法中只是隐式传递'this'指针的函数,'this'可以像任何其他指针一样被检查为NULL。显然,即使它没有崩溃,这段代码也会让人感到困惑和不好。在调试器中单步调试代码会非常混乱,看到一个NULL指针即将有一个调用它的方法,然后看不到预期的崩溃。我的问题是:它是否违反了C ++标准来调用SomeFooPtr->bar() SomeFooPtr == NULL

我觉得它可能不是因为用户定义的操作符 - >返回一个指针,这意味着即使该指针为NULL,它肯定没有被解除引用(取消引用一个NULL指针,我确信该标准被视为非法或未定义)。另一方面,原始指针的语义不一定必须与用户定义的指针的语义匹配 - 可能是operator->即使编译器不会生成一个,也将它们视为取消引用。

5 个答案:

答案 0 :(得分:13)

这可能适用于大多数系统,但它是未定义的行为。标准:

  

5.2.5.3

     

如果E1的类型为“指向类X的指针”,则表达式E1->E2将转换为等效形式(*(E1)).E2 [...]

  

5.2.5.1

     

后缀表达式,后跟点.或箭头->,可选地后跟关键字template(14.8.1),然后是 id-表达式,是一个后缀表达式。评估点或箭头之前的后缀表达式; 58) [...]

     

58)即使结果不需要确定整个后缀表达式的值,也会发生此评估,例如,如果id-expression表示静态成员。

评估*x其中x是一个空指针会导致未定义的行为,所以在你输入函数之前,很明显是UB的情况。

答案 1 :(得分:7)

即使取消引用不是UB,此测试也会被破坏。当多重继承的调整进入游戏时,它会中断:

#include <stdio.h>
class B
{
    int value;
    public:
    void foo()
    {
        if (!this)
            printf("this==0\n");
        else 
            printf("safe\n");
    }
};
class A { public: int anotherValue; };
class Z : public A,public B {};

int main()
{
    Z *z=0;
    z->foo();
}

在这里打印“安全”。

答案 2 :(得分:1)

如果它是合法的并不重要,这对读者来说是混乱的。在此代码有效的实现中,vtable是按类型访问的,当然不是按对象访问。

此外,我希望这段代码可以用于覆盖构造函数失败,这会掩盖其他地方的各种问题。应该正确处理构造函数失败,而不是像示例那样令人讨厌的kludge。

答案 3 :(得分:1)

这是(现在一起)未定义的行为。但是,对于许多编译器来说,它将起作用,附加约束条件必须是非虚拟的。

答案 4 :(得分:1)

是UB。使其崩溃的一个好方法是将它用作使用多继承的派生类的基类。 YMMV。