
From: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] On Behalf Of Emil Dotchevski Sent: March-18-11 3:11 AM On Thu, Mar 17, 2011 at 3:22 PM, Ted Byers
wrote: From: boost-users-bounces@lists.boost.org Sent: March-17-11 5:27 PM On Thu, Mar 17, 2011 at 1:58 PM, Ted Byers
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.
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
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. 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