-->

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

2020-03-01 03:04发布

问题:

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?

回答1:

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.



回答2:

Here's an example (not that I recommend writing such code):

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>();
}

This is perfectly fine code that does not exhibit UB. This is possible because std::shared_ptr uses type-erasure; the final call to delete will delete a derived*, even if the last std::shared_ptr to trigger destruction is of type std::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.



回答3:

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.