Boost logo

Boost Users :

Subject: Re: [Boost-users] boost::exception_detail::error_info_base does not have virtual destructor
From: Ted Byers (r.ted.byers_at_[hidden])
Date: 2011-03-18 08:37:19


>From: boost-users-bounces_at_[hidden]
[mailto:boost-users-bounces_at_[hidden]] On Behalf Of Emil Dotchevski
>Sent: March-18-11 3:11 AM
>On Thu, Mar 17, 2011 at 3:22 PM, Ted Byers <r.ted.byers_at_[hidden]> wrote:
>>>From: boost-users-bounces_at_[hidden]
>>>Sent: March-17-11 5:27 PM
>>>On Thu, Mar 17, 2011 at 1:58 PM, Ted Byers <r.ted.byers_at_[hidden]> wrote:
>>>
>>The virtual destructor warning goes directly against a conscious
>>>design
>> decision. In my opinion it also teaches programmers a bad habit. This
>>> doesn't make the warning any less annoying of course, so I'm doing my
>> best to suppress it.
>>
>> I would like to understand why making destructors virtual when there
>> are other virtual member functions might be seen as a bad habit.
>
>OK I'm exaggerating, obviously there are worse habits one can be taught. :)
>
>A public virtual destructor lets anyone call delete as they please. In any
non-trivial program this isn't a good thing.
>
Why? You create classes to manage certain resources as you need them, and
get rid of them when you don't. And, actually, when the pointer to new
acquired instance of a class is placed within a hared pointer, you don't
have to explicitly call delete. Instead, you let the smart pointer do it.

>> What, precisely, was that conscious design decision, and what is the
>> rationale for it?
>
>"The error_info_base class does not support deleting objects of derived
types polymorphically" (and virtual is used to indicate that a particular
operation is polymorphic, which would be misleading in this
>case.)
>
>> It is my experience that when two experienced developers disagree
>> about a practice, it is born of differences in the nature of the
>> problems they have faced in the past, and the information they have at
>> their disposal.  If you were to look at the applications I develop,
>> you'd find very few objects created on the stack.  Almost everything
>> goes on the heap, managed by the most appropriate of the boost smart
>> pointers.  In my environmental modelling software, for example, the
>> application starts off with almost nothing in the heap, but as the
>> user builds the model, he may end up producing hundreds or even
>> thousands of instances of sometimes complex UDTs, and these UDTs are
>> often drawn from complex inheritance trees (but almost never involving
>> multiple inheritance ;-).  Connections between these instances can
>> often be quite complex, so there is, in the base class, a function that
breaks all connections among the objects before any attempt is made to
delete anything.
>> Because the number of UDTs is quite large, and there is a common
>> modelling interface for which there are virtual functions (as pure
>> virtual functions in the base class), all these objects are managed in
>> a single std::vector containing smart pointers having pointers to the
base class.
>
>What is the reason for not storing shared_ptrs in that std::vector?
Actually, paraphrasing myself, what I had written was that the pointers to
these objects are cast to pointers to the base class and placed in smart
pointers (usually boost::shared_ptr), and these smart pointers are placed in
the std::vector.

>Wouldn't a protected and non-virtual destructor be more appropriate in that
case?

How could a protected, non-virtual destructor be appropriate here at all?

You have a single container of smart pointers to a base class. But the
actually instances there represent possibly hundreds of different derived
classes, generally with very different storage requirements. These are all
objects on the heap, so all were created initially using operator new.
Operator delete has thus to be called on each of them, and if the destructor
is not virtual, you'd have to cast back to the real UDT in order to delete
them. Since they are pointers to the base class, you'd have to try a
dynamic cast each to every known UDT in order to get a pointer to the right
class in order to properly delete it. That would be an unmaintainable
nightmare that is completely avoidable simply by using a virtual destructor
and the combination of pointers to the base class living in shared pointers
living in turn in a std::vector. The number of UDTs is huge and continually
growing (for the biota portion of the model, there are typically UDTs for
genera and species, and since there are so many species on the planet, I
will probably not live long enough to see UDTs made for all of them).

Cheers,

Ted


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net