为什么析构函数默认不是虚拟的[C ++]

Why are destructors not virtual by default [C++]

为什么C++没有为具有至少一个其他虚函数的类默认析构函数虚化?在这种情况下,添加一个虚拟析构函数不需要花费任何代价,而没有一个是(几乎是?)总是一个bug。C++ 0x会解决这个问题吗?


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

也许你在想,只有vtable的存在才是唯一的开销。但是每个单独的函数分派也必须考虑,如果我想让析构函数直接调用分派,应该允许这样做。

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

编辑:让我把西蒙的精彩评论放到这里:看看这个关于为析构函数生成的代码的问题。如您所见,还需要考虑代码膨胀的开销。


下面是一个例子(我不建议编写这样的代码):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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_ptrstd::shared_ptr类型。

请注意,std::shared_ptr的这种行为不是为虚拟破坏而定制的;它有多种其他用途(例如std::shared_ptr { std::fopen( ... ), std::fclose })。然而,由于这种技术已经支付了一些间接操作的成本,一些用户可能对为其基类拥有虚拟析构函数不感兴趣。这就是"只为你需要的东西付钱"的意思。


根据标准的字母,具有非虚拟析构函数的多态类不是bug。对这样一个对象执行一个特定的操作会导致不确定的行为,但其他的一切都是完全洁净的。因此,考虑到本标准在允许程序员犯什么错误方面的宽松行为,为什么应该对析构函数进行特殊处理?

这样的更改将带来成本,尽管大部分是微不足道的:虚拟表将是一个更大的元素,以及与析构函数调用相关联的虚拟分派。

据我所知,在C++ 11中,析构函数的行为没有变化。我想它会在关于特殊成员函数的小节中说些什么,但它不会,而且一般来说,虚拟函数的小节中也没有类似的内容。