Re: [boost] throw_exception rev. 44954 -> g++ warnings

Right, warning free code is a good idea.
Nevertheless one should specify Boost include path via -isystem path/to/boost and not via -I path/to/boost if one doesn't want to see the warnings in system libraries with gcc.
That's a bit like putting black tape over a "check-engine" light. My primary question still is: What is the disadvantage of adding the virtual destructors? The Stroustrup book has a very clear recommendation (below). Why not follow this advice? I'm keen to learn the facts. Ralf Stroustrup 2000 Section 12.4.2 (page 319 in my edition): Many classes require some form of cleanup for an object before it goes away. Since the abstract class lval_box cannot know if a derived class requires such cleanup, it must assume that it does require some. We ensure proper cleanup by defining a virtual destructor lval_box::~lval_box() in the base and overriding it suitably in derived classes. ... ... We have no way of knowing exactly to which class the object pointed to by p belongs, but thanks to lval_box's virtual destructor, proper cleanup as (optionally) defined by that class' destructor will be called.

Ralf W. Grosse-Kunstleve:
My primary question still is: What is the disadvantage of adding the virtual destructors? The Stroustrup book has a very clear recommendation (below). Why not follow this advice? I'm keen to learn the facts.
A destructor that is never supposed to be called (except by the destructor of the derived class) doesn't need to be virtual. There's not much point in trying to avoid the undefined behavior in "delete sp.get()". sp is now a time bomb. A protected destructor, on the other hand, yields a compile-time error. You can still make it virtual if you like. It's a bit contradictory for the reader as you appear unable to make up your mind as to whether the destructor is supposed to be part of the base class interface or not, but most of them are familiar with g++ by now, so they won't be confused for long.

Right, warning free code is a good idea.
Nevertheless one should specify Boost include path via -isystem path/to/boost and not via -I path/to/boost if one doesn't want to see the warnings in system libraries with gcc.
That's a bit like putting black tape over a "check-engine" light. My primary question still is: What is the disadvantage of adding the virtual destructors? The Stroustrup book has a very clear recommendation (below). Why not follow this advice? I'm keen to learn the facts. Ralf
Stroustrup 2000 Section 12.4.2 (page 319 in my edition):
Many classes require some form of cleanup for an object before it goes away. Since the abstract class lval_box cannot know if a derived class requires such cleanup, it must assume that it does require some. We ensure proper cleanup by defining a virtual destructor lval_box::~lval_box() in the base and overriding it suitably in derived classes. ... ... We have no way of knowing exactly to which class the object pointed to by p belongs, but thanks to lval_box's virtual destructor, proper cleanup as (optionally) defined by that class' destructor will be called.
What's the problem with making the destructor virtual in the first place? Since the class already has other virtual functions this won't generate any (significant) additional overhead (the only thing what's added is another function pointer to the already existing virtual function table, barely something to worry about). Regards Hartmut

On Sat, May 3, 2008 at 8:00 AM, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote:
What's the problem with making the destructor virtual in the first place? Since the class already has other virtual functions this won't generate any (significant) additional overhead (the only thing what's added is another function pointer to the already existing virtual function table, barely something to worry about).
I am not concerned about overhead. In C++, you use virtual function calls only when your design requires polymorphic behavior. My design does not. If GCC issued a warning if you have a non-virtual function in a class that has some virtual functions, would you make the non-virtual function virtual? (hint: much like the destructor case, using non-virtual function in the first place _could_ be a serious bug.) Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

What's the problem with making the destructor virtual in the first
On Sat, May 3, 2008 at 8:00 AM, Hartmut Kaiser <hartmut.kaiser@gmail.com> wrote: place?
Since the class already has other virtual functions this won't generate any (significant) additional overhead (the only thing what's added is another function pointer to the already existing virtual function table, barely something to worry about).
I am not concerned about overhead.
In C++, you use virtual function calls only when your design requires polymorphic behavior. My design does not.
Actually, your class _is_ polymorphic, because otherwise you didn't have any virtual functions in it. You should be aware of the fact that others might use it as a base class and as soon as it is polymorphic, they might expect their destructors to be called.
If GCC issued a warning if you have a non-virtual function in a class that has some virtual functions, would you make the non-virtual function virtual? (hint: much like the destructor case, using non-virtual function in the first place _could_ be a serious bug.)
Your theoretical assumption is completely off topic because neither of those are special functions, and no sane compiler never ever would complain about this. But leaving aside this, yes I would make my base class functions virtual if somebody had a (even remote) chance of having his code broken because of a missing virtual keyword. Regards Hartmut

What's the problem with making the destructor virtual in the first
Hartmut wrote: place?
Since the class already has other virtual functions this won't generate any (significant) additional overhead (the only thing what's added is another function pointer to the already existing virtual function table, barely something to worry about).
This is not true. In this case, the destructor is a no-op. Virtual functions incur significant overhead over non-virtual functions in the case that the non-virtual would be inlined, where-as the virtual must have a symbol for the pointer in the virtual function table to point to, and cannot be called inline unless the exact type is known at compile time (defeating the purpose of polymorphism.) Consider the difference between this: inline ~classname() {} //do nothing inline virtual ~classname() {} //do nothing but pay function call overhead anyway because the compiler usually can't inline the function. There seems to be a widespread misconception that virtual functions have low overhead. This can be true, but when loss of potential inlining happens it is a significant overhead. This may seem like a small issue until you profile code that spends double digit percentage of runtime executing an out-of-line function call to a no-op destructor. Luke

Simonson, Lucanus J wrote:
What's the problem with making the destructor virtual in the first
Hartmut wrote: place?
Since the class already has other virtual functions this won't generate any (significant) additional overhead (the only thing what's added is another function pointer to the already existing virtual function table, barely something to worry about).
This is not true. In this case, the destructor is a no-op. Virtual functions incur significant overhead over non-virtual functions in the case that the non-virtual would be inlined, where-as the virtual must have a symbol for the pointer in the virtual function table to point to, and cannot be called inline unless the exact type is known at compile time (defeating the purpose of polymorphism.)
Do you realize that you just made an argument why it is important for the destructor to be virtual ? If the compiler doesn't know the exact type (and thus can't inline the call), there is a serious risk that any derived destructor might need to be executed, but the compiler doesn't know that (and neither does the runtime, as there is no entry for the destructor in the vtable). It doesn't matter whether the base-class destructor is a no-op. What matters is what is in the derived class destructor, which you (or the base class implementor) does not have any control over. Regards, Stefan -- ...ich hab' noch einen Koffer in Berlin...

Do you realize that you just made an argument why it is important for the destructor to be virtual ? If the compiler doesn't know the exact type (and thus can't inline the call), there is a serious risk that any derived destructor might need to be executed, but the compiler doesn't know that (and neither does the runtime, as there is no entry for the destructor in the vtable). It doesn't matter whether the base-class destructor is a no-op. What matters is what is in the derived class destructor, which you (or the base class implementor) does not have any control over.
I clearly understand the reason why the destructor of polymorphic types should be declared virtual. I was trying to make an argument against polymorphism in general, because it produces much greater runtime overhead than most people seem to appreciate when used on simple types that should be heavily inlined. In fact, I don't myself understand the reason Emil has for not declaring the destructor virtual in this case. He said he didn't care about overhead, after all. I was simply pointing out that the overhead is greater than what Hartmut suggested. So great, in fact, that I prefer to avoid polymorphic programming style for that very reason. Thanks, Luke

Simonson, Lucanus J wrote:
I clearly understand the reason why the destructor of polymorphic types should be declared virtual. I was trying to make an argument against polymorphism in general, because it produces much greater runtime overhead than most people seem to appreciate when used on simple types
Hmm, 'much greater runtime overhead' is quite strong. This needs to be backed up for every particular case, to assess the real impact. Otherwise any such concern is just premature optimization.
that should be heavily inlined. In fact, I don't myself understand the
Even inlining itself can have (negative) impact on performance, as you increase code size. And, speaking of performance, there are sometimes good reasons not to use exceptions (not even exception *specifiers*), since this involves added synthesized code that incurs performance overhead. So, whether that particular case of 'virtual' is worth all the trouble is questionable.
reason Emil has for not declaring the destructor virtual in this case. He said he didn't care about overhead, after all. I was simply pointing out that the overhead is greater than what Hartmut suggested. So great, in fact, that I prefer to avoid polymorphic programming style for that very reason.
Yes, understood. Thanks, Stefan -- ...ich hab' noch einen Koffer in Berlin...

AMDG Stefan Seefeld wrote:
Simonson, Lucanus J wrote:
This is not true. In this case, the destructor is a no-op. Virtual functions incur significant overhead over non-virtual functions in the case that the non-virtual would be inlined, where-as the virtual must have a symbol for the pointer in the virtual function table to point to, and cannot be called inline unless the exact type is known at compile time (defeating the purpose of polymorphism.)
Do you realize that you just made an argument why it is important for the destructor to be virtual ?
If the compiler doesn't know the exact type (and thus can't inline the call), there is a serious risk that any derived destructor might need to be executed, but the compiler doesn't know that (and neither does the runtime, as there is no entry for the destructor in the vtable).
It doesn't matter whether the base-class destructor is a no-op. What matters is what is in the derived class destructor, which you (or the base class implementor) does not have any control over.
In this case, the author knows that when the object is deleted, its dynamic type is the same as its static type. The compiler may not be able to figure this out. In Christ, Steven Watanabe
participants (7)
-
Emil Dotchevski
-
Hartmut Kaiser
-
Peter Dimov
-
Ralf W. Grosse-Kunstleve
-
Simonson, Lucanus J
-
Stefan Seefeld
-
Steven Watanabe