在成员函数中测试this-pointer是合法的C ++吗?

时间:2013-01-08 14:58:04

标签: c++ null this

我有一个涉及不同类类型对象的应用程序。对象由指针引用。空指针表示关联的对象不存在。目前,调用代码很麻烦,因为每次使用指向对象的指针时,它都会测试指针值为null,并采取一些适当的操作,它为null。因为在不存在的情况下要采取的默认操作取决于对象的类型,我宁愿在对象本身的类中而不是在调用程序中对其进行编码。这导致如下构造:

class C
{ ... 
  void member_func() //non-virtual !
  { if (this) { do something with the object ... }
    else { take some default action }
  }
  ...
};

显然,成员函数不能是虚拟的,因为当对象不存在时查找表不存在,并且虚拟调用将失败。但这个代码是否适用于非虚拟成员函数的合法C ++?它似乎对我尝试过的编译器工作正常,但我担心可能的不可移植性。在标准中,我找不到明确允许或明确禁止此类结构的条款。

5 个答案:

答案 0 :(得分:12)

this在成员函数中永远不会为null,因此您执行的检查无效。

Matthieu M.在评论中指出,如果你在代码中做了类似的事情:

C* c = 0; 
c->member();

这会导致未定义的行为,这就是错误

答案 1 :(得分:6)

正如已经指出的那样,this永远不能是空指针。如果是,您已经调用了未定义的行为。相反,您可以创建一组重载函数,如下所示:

void DoTheThing(C* cp)
{
    if (cp)
        cp->member_func();
    else
    {
        // take some default action
    }
}

void DoTheThing(B* bp)
{
    if (bp)
        bp->some_other_member_func();
    else
    {
        // take some default action
    }
}

如果要调用的函数在每个类中具有相同的名称,那么您可以在每个类中创建一个静态函数,该函数执行该类的默认操作(都具有相同的名称),并创建一个模板: / p>

template<typname T>
void DoTheThing(T* tp)
{
    if (tp)
        tp->member_func();
    else
        T::default_action()
}

答案 2 :(得分:1)

标准方面,代码不合法​​,它在实践中使用(不好的做法)。

事实上,IIRC MFC在内部使用这些检查。

答案 3 :(得分:1)

检查 this == NULL是否有问题。 通过NULL对象指针调用方法是。

如果要将检查保留在某处,可以将其放在智能指针类中,如果保持的指针为NULL,则可以采取适当的操作。如果“适当的操作”由保持的类型唯一确定,则可以使用特征类来指定它。

这样,您的NULL检查及其逻辑将保持在一起,而不会混合到调用者或方法代码中。


// specialize this to provide behaviour per held type
template <typename T> struct MaybeNullDefaultAction {
    void null_call() { throw std::runtime_error("call through NULL pointer"); }
}

template <typename T> class MaybeNull: MaybeNullDefaultAction<T> {
    T *ptr;
public:
    explicit MaybeNull(T *p) : ptr(p) {}

    T* operator-> () {
        if (!ptr)
            null_call();
        // null_call should throw to avoid returning NULL here
        return ptr;
    }
};

不幸的是,我没有办法在没有投掷的情况下做到这一点。没有办法拦截所有方法名称的函数调用,否则我只需从*this返回operator->并在operator()中完成工作。

答案 4 :(得分:0)

我认为,不允许这样做。您要求参考该标准。我相信首先感兴趣的是9.3.1非静态成员函数,1。:

  

可以为其类的对象调用非静态成员函数   类型,或从类中派生的类的对象(第10条)   类型,使用类成员访问语法(5.2.5,13.3.1.1)。

第二步,看看5.2.5 Class member access,2。:

  

将表达式E1-> E2转换为等价形式(*(E1))。   5.2.5的其余部分将仅解决第一个选项(点)。

因此,如果E1是nullptr,则不允许* E1。所以至少是我的猜测。