执行“删除此”操作时缺少虚拟析构函数
C++ FAQ Lite 的 16.15 部分讨论了 < code>删除此然后提到:
当然,通常的警告适用于 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条目不准确,还是我误解了它?
Section 16.15 of the C++ FAQ Lite discusses delete this
and then mentions:
Naturally the usual caveats apply in cases where your this pointer is
a pointer to a base class when you don't have a virtual destructor.
Why is this true? Consider this code:
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;
}
};
Used thus:
int main()
{
ISuicidal* p = new MyKlass;
p->suicide();
return 0;
}
In the call p->suicide()
, the destructor of MyKlass
is called as expected, even though ISuicidal
has no virtual destructor.
To me this makes sense, because in MyKlass::suicide
, the static type of this
is known to be MyKlass*
, so the correct destructor is invoked. This is easy to verify by placing typeid
calls inside suicide
.
So is the FAQ entry inaccurate, or am I misunderstanding it?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
你误会了。在ISuicidal中实现自杀函数(即delete this),你会发现当this指针是基类时,对其调用delete并不会调用派生类的析构函数。
You are misunderstanding. Implement the suicide function (ie delete this) in ISuicidal and you will find that when the this pointer is a base class calling delete on it doesn't call the derived class's destructor.
在你的函数
suicide(),
您正在使用
删除此;
这里,
this
指针对应于类MyKlass,因为该函数是在MyKlass中定义的,而不是在ISuicidal中,因此调用了MyKlass的析构函数。如果您在 ISuicidal 中定义了该函数,那么它不会调用 MyKlass 的析构函数,除非您在 ISuicidal 中声明虚拟析构函数。
In your function
suicide(),
You are using
delete this;
Here, the
this
pointer corresponds to the class MyKlass, as the function is defined in MyKlass and not ISuicidal, and therefore the destructor of MyKlass is called.If you had defined the function in ISuicidal, then it would not call the destructor of MyKlass unless you declare a virtual destructor in ISuicidal.
如果您在派生自 MyClass 的层次结构中引入另一个实际类(例如 MyClass2),就会出现问题。
the problem arises if you introduce another real class in the hierarchy that derives from MyClass (e.g. MyClass2).
子类:public MyKlass {
〜孩子(){}
};
ISuicidal* p = new Child;
p->suicide(); // ~Child() 未调用!
class Child : public MyKlass {
~Child () {}
};
ISuicidal* p = new Child;
p->suicide(); // ~Child() not called !
我认为你误解了它。当您在基类中调用 delete this 时,即 this 指针具有指向基类的指针类型时,就会出现此问题。
在您的示例中,这不是指向基类的指针,而是指向派生类的指针。
I think you're misunderstanding it. The issue occurs when you call delete this in the base class, that is when the this pointer has a type of pointer to the base class.
In your example this is not a pointer to the base class but rather a pointer to the derived class.
只要您调用实例的确切析构函数(例如,不调用基类的析构函数),它就是安全的。
因此,您可以通过为每个子类正确实现
suicide()
来安全地实现这一点 - 或者通过创建一个可由this
访问的外部删除器函数(或任何管理这个
)。it's safe as long as you call the exact destructor of the instance (e.g. do not call the destructor of a base).
therefore, you can safely accomplish this by properly implementing
suicide()
for every subclass - or by creating an external deleter function which is accessible tothis
(or whatever manages the lifetime ofthis
).