Why are destructors not virtual by default [C++]
Asked Answered
E

3

34

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?

Ehrsam answered 8/7, 2011 at 1:31 Comment(5)
The keyword is almost. If your base has virtual functions and you don't want to pay for the virtual destructor how do you specify its not virtual in this new world. Also what happens to all the old code? We need a plan to deal with the backward compatibility issues.Annunciator
The virtual destructor has a cost, in that it requires another copy of the destructor code, for all derived classes. See this question.Godric
possible duplicate of Why not have all the functions as virtual in cppAccount
@Simon, the D0 variant can be implemented as a wrapper around D1, though.Hardaway
not a possible duplicate, I understand why not all functions are virtual by default. My question was why doesn't C++ make destructors virtual by default as soon as you declare one other function virtual.Ehrsam
C
23

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.

Castalia answered 8/7, 2011 at 1:46 Comment(0)
S
3

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.

Stable answered 8/7, 2011 at 5:30 Comment(0)
C
2

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.

Cerberus answered 8/7, 2011 at 1:53 Comment(2)
Was there ever a plan to make virtual destructors the default in C++0x? I ask because I came across this paper: www2.research.att.com/~bs/C++0x_panel.pdf which says there was at the bottom, but I haven't been able to find any more info about it.Ehrsam
@dacode: I did not follow the actual meetings and whatnot, so I don't know. Of the four "embarrassments", only the last was actually changed. I wouldn't be surprised if somebody submitted a proprosal for such a change, but why it was voted down I can not say.Cerberus

© 2022 - 2024 — McMap. All rights reserved.