执行"delete this"时缺少虚拟析构函数



c++ FAQ Lite的16.15节讨论了delete this,然后提到:

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

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

class ISuicidal {
public:
    virtual void suicide() = 0;
};
class MyKlass : public ISuicidal {
public:
    MyKlass() {
        cerr << "MyKlass constructorn";
    }
    ~MyKlass() {
        cerr << "MyKlass destructorn";
    }
    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条目不准确,还是我误解了它?

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

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

如果在ISuicidal中定义了函数,则它不会调用myclass的析构函数,除非在ISuicidal中声明了虚析构函数。

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

class ISuicidal {
public:
    virtual void suicide() = 0;
};
class MyKlass : public ISuicidal {
public:
    MyKlass() {
       cerr << "MyKlass constructorn";
    }
    ~MyKlass() {
        cerr << "MyKlass destructorn";
    }
    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;
}

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

ISuicidal* p = new Child;

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

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

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

在你的例子中,这不是一个指向基类的指针,而是一个指向派生类的指针。

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

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

相关内容

  • 没有找到相关文章

最新更新