30

为什么 C++ 默认情况下不为至少有一个其他虚函数的类使析构函数变为虚拟? 在这种情况下,添加虚拟析构函数不会花费我任何成本,而且没有(几乎?)总是一个错误。C++0x 会解决这个问题吗?

4

3 回答 3

21

你不需要为你不需要的东西付费。如果您从不通过基指针删除,您可能不希望间接析构函数调用的开销。

也许您认为 vtable 的存在是唯一的开销。但是也必须考虑每个单独的函数调度,如果我想直接让我的析构函数调用调度,我应该被允许这样做。

我想,如果您确实删除了一个基指针并且该类具有虚拟方法,那么您的编译器会很好地警告您。

编辑:让我在这里拉西蒙的优秀评论:在为析构函数生成的代码上查看这个 SO 问题。如您所见,还需要考虑代码膨胀开销。

于 2011-07-08T01:46:05.100 回答
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将删除 a derived*,即使最后std::shared_ptr触发销毁的类型是std::shared_ptr<void>

请注意,这种行为不是std::shared_ptr针对虚拟破坏量身定制的;它有多种其他用途(例如)。然而,由于这种技术已经付出了一些间接工作的代价,一些用户可能对为他们的基类使用虚拟析构函数不感兴趣。这就是“只为你需要的东西付费”的意思。std::shared_ptr<FILE> { std::fopen( ... ), std::fclose }

于 2011-07-08T05:30:49.470 回答
2

按照标准的规定,具有非虚拟析构函数的多态类不是错误。对此类对象执行的一项特定操作会导致未定义的行为,但其他一切都是完美的。那么考虑到标准在允许程序员犯什么错误方面的宽松行为,为什么要对析构函数进行特殊处理呢?

这样的改变会产生成本,尽管大部分是微不足道的:虚拟表将大一个元素,并且虚拟调度与析构函数调用相关联。

据我所知,不,C++11 中的析构函数在这方面的行为没有变化。我想它会在关于特殊成员函数的部分中说些什么,但它没有,而且在一般的虚函数部分中同样没有任何内容。

于 2011-07-08T01:53:13.630 回答