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*,所以调用了正确的析构函数。这很容易通过在typeid内部调用来验证suicide

那么FAQ条目是不准确的,还是我误解了它?

4

6 回答 6

5

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

于 2011-09-16T06:03:47.747 回答
4

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

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

于 2011-09-16T06:06:52.230 回答
2

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

ISuicidal* p = new Child;

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

于 2011-09-16T07:29:28.970 回答
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;
}
于 2011-09-16T06:09:12.550 回答
0

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

因此,您可以通过为每个子类正确实现suicide()- 或通过创建一个可访问的外部删除器函数this(或任何管理this.

于 2011-09-16T06:03:41.943 回答
0

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

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

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

于 2011-09-16T06:05:09.633 回答