1
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?
}

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

4

2 回答 2

2

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

B::~B()执行时,对象的类型是B(如果你调用f()然后,你将被调度到B::f()

A::~A()执行时,对象的类型是A,如果你调用f(),你会根据 §10.4[class.abstract]/6 得到未定义的行为

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

或者,正如 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()

于 2013-08-27T03:16:24.427 回答
1

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

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

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

于 2013-08-27T03:18:01.583 回答