做“删除这个”时缺少虚拟析构函数

时间:2011-09-16 05:58:55

标签: c++ polymorphism virtual-destructor self-destruction

16.15 of the C++ FAQ Lite部分讨论delete this,然后提及:

  

当然,通常的警告适用于此指针所在的情况   当你没有虚拟析构函数时指向基类的指针。

为什么这是真的?请考虑以下代码:

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
        cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

因此使用:

int main()
{
    ISuicidal* p = new MyKlass;
    p->suicide();
    return 0;
}

在调用p->suicide()中,MyKlass的析构函数按预期调用,即使ISuicidal没有虚拟析构函数

对我来说这是有道理的,因为在MyKlass::suicide中,this的静态类型已知为MyKlass*,因此调用了正确的析构函数。通过将typeid调用放在suicide内,可以轻松验证这一点。

FAQ条目不准确,还是我误解了?

6 个答案:

答案 0 :(得分:4)

你是误会。在ISuicidal中实现自杀函数(即删除它),你会发现当this指针是一个调用delete的基类时,它不会调用派生类的析构函数。

答案 1 :(得分:4)

在你的函数中suicide(), 您正在使用delete this;
这里,this指针对应于MyKlass类,因为函数在MyKlass中定义而不是ISuicidal,因此调用MyKlass的析构函数。

如果您在ISuicidal中定义了该函数,那么除非您在ISuicidal中声明虚拟析构函数,否则它不会调用MyKlass的析构函数。

答案 2 :(得分:2)

如果在层次结构中引入另一个派生自MyClass的实际类(例如MyClass2),则会出现问题。

class ISuicidal {
public:
    virtual void suicide() = 0;
};

class MyKlass : public ISuicidal {
public:
    MyKlass() {
       cerr << "MyKlass constructor\n";
    }

    ~MyKlass() {
        cerr << "MyKlass destructor\n";
    }

    void suicide() {
        delete this;
    }
};

class MyKlass2 : public MyKlass {
public:
    MyKlass2() {
        cerr << "MyKlass2 ctr"<<std::endl;
    } 

    ~MyKlass2() {
        cerr << "MyKlass2 dtr"<<std::endl;
    }
}

int main()
{
    MyKlass* p = new MyKlass2;
    delete p; //destructor of base class called, not the destructor of MyKlass2 because
              //the destructor is not virtual
    return 0;
}

答案 3 :(得分:2)

class Child : public MyKlass { ~Child () {} };

ISuicidal* p = new Child;

p->suicide(); // ~Child() not called !

答案 4 :(得分:0)

只要你调用实例的确切析构函数(例如,不要调用基类的析构函数),它就是安全的。

因此,您可以通过为每个子类正确实现suicide()或通过创建this可访问的外部删除函数(或管理this生命周期的任何内容)来安全地实现此目的。 )。

答案 5 :(得分:0)

我认为你误解了它。当您在基类中调用delete this时,即当this指针具有指向基类的指针类型时,就会出现此问题。

  

当然,通常的警告适用于此指针所在的情况   当你没有虚拟析构函数时指向基类的指针。

在您的示例中,这不是指向基类的指针,而是指向派生类的指针。