在虚拟析构函数中调用其他虚拟方法是否安全?

时间:2013-08-27 03:09:37

标签: c++ c++11 polymorphism destructor

struct A
{
    virtual ~A() { this->f(); }

    virtual void f() {};
};

struct B : A
{
    int* p;

    B() : p(new int) {}

    ~B()
    {
        delete p;
        p = 0;
    }

    void f() override { *p = 0; }
};

int main()
{
    delete new B; // Is it safe?
}

在虚拟析构函数中调用其他虚方法是否安全?

2 个答案:

答案 0 :(得分:2)

如果你知道规则是安全的,并且规则说在析构函数中,对象的动态类型是析构函数正在执行的类。

正在执行B::~B()时,对象的类型为B(如果您拨打f(),则会发送给B::f()

A::~A()正在执行时,对象的类型为A,如果您调用f(),则根据§10.4得到未定义的行为[class.abstract] / 6 < / p>

  

可以从抽象类的构造函数(或析构函数)调用成员函数;对于从这样的构造函数(或析构函数)创建(或销毁)的对象,直接或间接地对纯虚函数进行虚拟调用的效果是未定义

或者,正如clang ++报告的那样,

test.cc:5:20: warning: call to pure virtual member function 'f'; overrides of 'f' in subclasses are not available in the destructor of 'A'
    virtual ~A() { this->f(); }
                   ^
test.cc:7:5: note: 'f' declared here
    virtual void f() = 0;
    ^
1 warning generated.

编辑:OP编辑纯虚拟出..所以,当A::~A()正在执行时,对f()的虚拟调用将被调度到A::f()

答案 1 :(得分:1)

注意:OP编辑了代码以删除纯虚拟部分。

根据您发布的内容,不是不安全。当您在继承层次结构中的类的构造函数或析构函数中调用虚函数时,它不像往常一样调用派生函数最多,而是调用当前类中定义的函数。

在这种情况下,~A调用没有函数体的A :: f(),所以这是一个错误。如果你为A :: f()提供了一个主体(你可以使用纯虚拟,只是在类定义之外),那么它将是“安全的”,尽管它是否能满足您的需求是另一回事。