执行“delete this”时缺少虚析构函数

3

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

当您没有虚构造函数时,如果您的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*,因此正确的析构函数被调用。这可以通过在suicide内部放置typeid调用来轻松验证。
那么FAQ条目是否不准确,还是我误解了它?
6个回答

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

4
在你的函数suicide()中,你使用了delete this;
这里,this指针对应于类MyKlass,因为该函数是在MyKlass中定义的,而不是ISuicidal,因此调用了MyKlass的析构函数。
如果你将函数定义在ISuicidal中,则不会调用MyKlass的析构函数,除非你在ISuicidal中声明一个虚析构函数。

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;
}

2

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

ISuicidal* p = new Child;

p->suicide(); // ~Child() 没有被调用 !

上述代码涉及到IT技术。子类Child继承了MyKlass类,但是没有实现析构函数。在第二行,使用new关键字创建了一个Child对象,并将其赋值给一个指向ISuicidal接口的指针p。然而,在调用p的suicide()方法后,我们发现~Child()并未被调用。

现在只有这样:行为未定义。 - curiousguy

0

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

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


0

我认为你误解了。问题发生在你在基类中调用delete this时,此时this指针的类型是指向基类的指针。

当你没有虚析构函数时,自然会出现这种情况,即你的this指针是指向基类的指针。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接