为什么析构函数默认不是虚拟的 [C++]
为什么 C++ 不默认将析构函数设为虚拟对于至少有一个其他虚函数的类?在这种情况下,添加虚拟析构函数不会花费我任何成本,而没有虚拟析构函数(几乎?)总是一种漏洞。 C++0x 会解决这个问题吗?
Why doesn't C++ make destructors virtual by default for classes that have at least one other virtual function? In this case adding a virtual destructor costs me nothing, and not having one is (almost?) always a bug. Will C++0x address this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您无需为不需要的东西付费。如果您从不通过基指针删除,您可能不希望间接析构函数调用的开销。
也许您认为 vtable 的存在就是唯一的开销。但是每个单独的函数调度也必须考虑,如果我想让我的析构函数直接调用调度,我应该被允许这样做。
我想,如果您确实删除了基指针并且该类具有虚拟方法,那么您的编译器最好会警告您。
编辑:让我在这里引用西蒙的精彩评论:查看这个关于为析构函数生成的代码的问题。正如您所看到的,还需要考虑代码膨胀开销。
You don't pay for what you don't need. If you never delete through base pointer, you may not want the overhead of the indirected destructor call.
Perhaps you were thinking that the mere existence of the vtable is the only overhead. But each individual function dispatch has to be considered, too, and if I want to make my destructor call dispatch directly, I should be allowed to do so.
It would be nice of your compiler to warn you if you do ever delete a base pointer and that class has virtual methods, I suppose.
Edit: Let me pull Simon's excellent comment in here: Check out this SO question on the code generated for destructors. As you can see, there's also code-bloat overhead to be considered.
这是一个例子(并不是我建议编写这样的代码):
这是非常好的代码,不会表现出 UB。这是可能的,因为 std::shared_ptr 使用类型擦除;即使最后一个触发销毁的
std::shared_ptr
类型为std,对
。delete
的最终调用也会删除衍生*
::shared_ptr请注意,{ std::fopen( ... ), std::fclose })。然而,由于这种技术已经付出了一些间接工作的成本,一些用户可能对为其基类使用虚拟析构函数不感兴趣。这就是“只为您需要的东西付费”的意思。
std::shared_ptr
的这种行为不是针对虚拟销毁而定制的;它还有多种其他用途(例如 std::shared_ptrHere's an example (not that I recommend writing such code):
This is perfectly fine code that does not exhibit UB. This is possible because
std::shared_ptr
uses type-erasure; the final call todelete
will delete aderived*
, even if the laststd::shared_ptr
to trigger destruction is of typestd::shared_ptr<void>
.Note that this behaviour of
std::shared_ptr
is not tailored to virtual destruction; it has a variety of other uses (e.g.std::shared_ptr<FILE> { std::fopen( ... ), std::fclose }
). However since this technique already pays the cost of some indirection to work, some users may not be interested in having a virtual destructor for their base classes. That's what "pay only for what you need" means.根据标准的字面意思,具有非虚拟析构函数的多态类不是错误。对这样一个对象执行的一个特定操作会导致未定义的行为,但其他一切都是完美的。因此,考虑到该标准在允许程序员犯的错误方面表现得很宽松,为什么要对析构函数给予特殊对待呢?
这样的改变会产生成本,尽管大部分都是微不足道的:虚拟表将增大一个元素,并且虚拟调度将与析构函数调用相关联。
据我所知,C++11 中析构函数在这方面的行为没有变化。我想它会在有关特殊成员函数的部分中提及一些内容,但事实并非如此,并且在一般虚拟函数部分中也同样没有任何内容。
By the letter of the standard, a polymorphic class with a non-virtual destructor is not a bug. One specific action performed on such an object results in undefined behavior, but everything else is perfectly kosher. So given the otherwise lenient behavior of the standard in terms of what mistakes it allows programmers to make, why should the destructor be given special treatment?
And such a change would have costs, albeit mostly trivial ones: the virtual table will be one element larger, and the virtual dispatch associated with destructor calls.
To the best of my knowledge, no, there is no change in the behavior of destructors in this regard in C++11. I imagine it would say something in the section on special member functions, but it does not, and there is similarly nothing in the section of virtual functions in general.