为什么C ++默认情况下不会将析构函数设置为虚拟用于至少具有一个其他虚函数的类?在这种情况下,添加虚拟析构函数不需要任何费用,而且没有一个(几乎? )总是一个bug。 C ++ 0x会解决这个问题吗?
答案 0 :(得分:20)
您不需要支付您不需要的费用。如果你永远不会通过基指针删除,你可能不需要间接析构函数调用的开销。
也许你认为仅仅存在vtable是唯一的开销。但是,每个单独的函数调度也必须考虑,如果我想让我的析构函数直接调用,我应该被允许这样做。
如果您确实删除了一个基本指针并且该类具有虚拟方法,那么编译器会警告您,这是很好的。我猜想。
编辑:让我在这里拉出Simon的优秀评论:查看this SO question关于为析构函数生成的代码。正如您所看到的,还需要考虑代码膨胀开销。
答案 1 :(得分:3)
这是一个例子(不是我建议编写这样的代码):
struct base {
virtual void foo() const = 0;
virtual void bar () const = 0;
};
struct derived: base {
void foo() const {}
void bar() const {}
};
std::shared_ptr<base>
make_base()
{
return std::make_shared<derived>();
}
这是完美的代码,没有展示UB。这是可能的,因为std::shared_ptr
使用了类型擦除;对delete
的最终调用将删除derived*
,即使触发销毁的最后一个std::shared_ptr
属于std::shared_ptr<void>
类型。
请注意std::shared_ptr
的此行为不为虚拟销毁量身定制;它有多种其他用途(例如std::shared_ptr<FILE> { std::fopen( ... ), std::fclose }
)。但是,由于这种技术已经支付了一些间接工作的成本,因此一些用户可能对其基类的虚拟析构函数不感兴趣。这就是“只为你需要的东西支付”的意思。
答案 2 :(得分:2)
通过标准的字母,具有非虚拟析构函数的多态类不是错误。对这样的对象执行的一个特定操作会导致未定义的行为,但其他一切都完全是犹太教的。因此,鉴于标准在程序员可能犯的错误方面的宽松行为,为什么要对析构函数进行特殊处理呢?
这样的改变会产生成本,虽然大部分是微不足道的:虚拟表将是一个更大的元素,以及与析构函数调用相关的虚拟调度。
据我所知,不,在这方面,C ++ 11中析构函数的行为没有变化。我想它会在关于特殊成员函数的部分中说些什么,但它没有,并且在一般的虚函数部分中也没有类似的内容。