Topic: Virtual functions and destructors
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/11/19 Raw View
martelli@cadlab.it (Alex Martelli) wrote:
>John Max Skaller <maxtal@suphys.physics.su.oz.au> writes:
> ...
>>>If that subclass is destroyed through a pointer to an ancestor whose
>>>dtor isn't virtual, undefined behaviour (violation of a "shall").
>
>>No no! Undefined behaviour is NOT a violation.
>
>No, but if the _program_ violates a "shall", undefined behaviour
>may result.
NO. My point is that this is NOT the case (as I understand it).
A "shall" on the program is to be interpreted as a requirement
on the compiler to issue a diagnostic.
>>where behaviour is undefined is the one place
>>it is IMPOSSIBLE for a "shall" to be violated,
>>because there isn't one :-)
>
>5.3.5 verse 3 says "the static type shall have a virtual destructor or
>the behaviour is undefined";
The wording in the Working Paper is NOT CONSISTENT (yet).
This clause is misworded. It SHOULD say "..if the static type
has a virtual destructor then ... (else behaviour is undefined)."
Technically, in C++ there is NO notion of a conforming
program and the Working Paper can NOT "shall" a programmer.
Unfortunately, much of the WP was lifted from the ARM
and the style therein addresses the programmer,
(as is appropriate for a reference manual) rather
than the implementor (as is appropriate for the C++ Standard).
(ISO C addresses both, C++ quite specifically and
deliberately does NOT).
Andrew has suggested fixing this with minimal editorial
changes by _defining_ "the program shall X" to mean
"if the program is not X, it is ill formed" -- which is
a constraint on the compiler to issue a diagnostic.
It is WOULD be possible to define a "shall" on the
program to mean "behaviour is undefined" INSTEAD. However,
it CANNOT simultaneously mean "ill formed if violated"
because the two things a diametrically
opposed notions: "ill formed" programs require a diagnostic,
behaviour is completely deterministic, undefined programs
require no diagnostic, indeed, all requirements on the
implementor are waived.
>So, the undefined behaviour "is NOT a violation", but it can _follow_
>from a violation on the program's part -- therefore, it's QUITE
>possible for a "shall" to _have been_ violated (by the program)
>where behaviour is (becomes) undefined.
Only in that AFTER a diagnostic is issued for an ill
formed program, all constraints on the implementor
are waived.
When the WP says "behaviour is undefined"
(or simply fails to defined behaviour), then it
is usually being quite specific in saying the
there is NO POSSIBLE VIOLATION by the compiler:
all bets are off.
To understand this another way: given some code,
the WP _always_ defines a range of permitted
behaviours:
1. Issue a diagnostic ("Ill formed")
2. Do exactly one thing ("Deterministic")
3. Do one of several things. ("Unspecified, non-deterministic")
4. Do anything. ("undefined behaviour").
So "undefined behaviour" is just the universal set,
and specific behaviour is just a singleton set,
-- including "ill formed". Nothing is more different
than these two sets!
A compiler is conforming if and only if it produces
a behaviour in the specified set (and has appropriate
documentation of implementation defined stuff).
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/11/19 Raw View
Dick Menninger <Dick.Menninger@daytonoh.attgis.com> wrote:
>Actually, "undefined behavior" is a precisely
>defined term in the WP, and not just a vague
>common term.
No. "behaviour" is a precisely defined term.
The WP proceeds to _define_ the SET of possible
behaviours which a given program must have
if compiled by a conforming translator.
By default, the set is the universal set.
Each case in the WP for which undefined
behaviour is stated is REDUNDANT, and is there
only to indicate completeness, or make
the English more comprehensible.
>In general, the application of this term to
>situations by the committee is based on the
>situation being potentially too hard to diagnose
>in some of its manifestations.
Yes. But that's the rationale for NOT
defining the behaviour as a subset
of the universal set.
>There is a commonsense "shall" where these
>situations are concerned. The programmer
>shall avoid these situations like the plague
>because the compiler will invariably do the first
>of the three permissible behaviors and not help
>detect it (Murphy's Law is they do not detect
>your case, whatever it is).
The point is that the CONFORMANCE TESTER
shall avoid these situations like the plague
because submiting a program which exhibits
"undefined behaviour" provides no opportunity
for measuring if the compiler is conforming
or not -- and so it's a waste of time.
On the the other hand the conformance
tester had better submit a substantial
suite of programs to the compiler,
all of which are ill formed, to check
if it issues mandatory diagnostics.
You might think that "ill formed" and "undefined behaviour"
were equivalent to the programmer, but you'd be wrong:
writing ill formed code is fine, because the compiler
is sure to catch it. (I do this deliberately all the
time). If the compiler doesn't catch it,
it isn't your fault -- complain to your vendor!
But you have to watch out very very carefully
for writing code with undefined behaviour.
Because if your hard disk gets wiped in that
case it's your fault. (yes, this HAS happened to
me once :-)
So the difference is in who has the responsibility
for detecting the fault.
[Products exist which take over some of these
responsibilities (eg memory leak detectors,
array bounds checkers, etc)]
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1995/11/22 Raw View
> ==========John Max Skaller, 11/19/95==========
> Unfortunately, much of the WP was lifted from the ARM
> and the style therein addresses the programmer,
> (as is appropriate for a reference manual) rather
> than the implementor (as is appropriate for the C++ Standard).
> (ISO C addresses both, C++ quite specifically and
> deliberately does NOT).
Well, it depends on your point of view whether that
was unfortunate or not. The ARM was an excellent
document that was useful and surprisingly clear for
both programmers and implementers. The current
DWP may be "legalistically" clear for implementers
(though even that is not certain) but it has lost clarity
of understanding in the process. It seems that such
an evolution may be inevitable in the standards process
but that is sad, if true. It should be possible for a
standard to communicate clearly to both. In fact,
I suspect that we would have much better and quicker
compliance with changes if it did speak more clearly
to implementers.
Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: parker@WPI.EDU (Chris Parker)
Date: 1995/11/09 Raw View
As a result of problems I'm having with C++ program execution, I need to
examine what the C++ standard says with respect to virtual destructors. I
understand these are a special case of virtualness and there are special
rules associated with how compilers are to support them.
Does C++ require you to declare your destructor virtual whenever you declare
any other member function in the class to be virtual?
Is it acceptable according to the standard for the destructor to be the only
virtual member in the class?
Is virtualness inherited by destructors? Does C++ automatically make all
applicable superclasses also have virtual destructor if they don't already?
If virtualness of destructors is inherited, then what is supposed to happen to
in the case where one of our subclasses uses multiple inheritance and one
of the other trees leading to the subclass doesn't declare destructors to be
virtual anywhere?
If anyone has any knowledge regarding what the C++ standard says about virtual
destructors, I'd appreciate it if you could answer any of the questions that
you can. I have all these situations occuring in a program I wrote, and I
don't understand why it is behaving as it is and the answers to those questions
would explain a lot of things for me. Thanks for any input you can provide.
Chris Parker
parker@cs.WPI.EDU
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Chris Parker <parker@owl.WPI.EDU>
Date: 1995/11/10 Raw View
> > Is it acceptable according to the standard for the destructor to be the onl
y
> > virtual member in the class?
>
> Sure, but it's kind of pointless. You only need a virtual destructor
> when you will be handling objects of a derived class through a pointer or
> reference whose static type is some base class, and in that case you will
> (nearly?) always need other virtual functions to provide the polymorphic
> interface that you'll use. The only exception I can imagine offhand
> would be if you were doing nothing but holding a bunch of them, as in a
> collection of some sort; but how could you ever do anything to the
> collected objects without virtual functions? Seems to me that the only
> thing you could do if they have no virtual function except the destructor
> is delete them, and if that's all you're doing... well, I suppose there
> could be some reason for deferring deletion for a bunch of mixed
> objects. It just doesn't seem real likely to me that that woudl be the
> ONLY action you'd want to take on them in a polymorphic fashion.
>
> But it's certainly legal to have only the destructor virtual.
You can do polymorphic things without any virtual functions. Casting a child
to a parent which has no virtual functions makes the class behave like it was
a class of that parent. You might want to delete it while it has been the
parent in a polymorphic sense. Thus, the destructor is the only virtual
function.
> > Is virtualness inherited by destructors? Does C++ automatically make all
> > applicable superclasses also have virtual destructor if they don't already?
>
> Is there any inheritance of anything from subclass to superclass? Or did
> you mean to write "subclass" there? Inheritance goes in only one
> direction: a class derived from a base class with a virtual destructor
> will have a virtual destructor. Deriving a class whose destructor is
> declared virtual from a base class with a non-virtual destructor doesn't
> magically change the base class in this respect (nor any other).
I did mean superclass when I said it. Based on what I've learned by thinking
about these things, I'm pretty convinced that all destructors should be
virtual all the time (implied). I can't find a single case where it would
make sense to destroy an object and not have all proper cleanup happen.
> dispatch. No magic, an object's actual type cannot affect anything done
> to it through a pointer or reference of a base type unless the operation
> is through a function that is virtual in that base type.
The thing that doesn't work for me is that the pointer type is
different, but it still has the same pointer value. At the low-level, you
are freeing the same block of memory either way. In order to
call a destructor, the system needs to convert the pointer to a class type
instance anyway.
Chris Parker
parker@cs.wpi.edu
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Chris Parker <parker@owl.WPI.EDU>
Date: 1995/11/10 Raw View
> > Is it acceptable according to the standard for the destructor to be the only
> > virtual member in the class?
>
> Sure, but it's kind of pointless. You only need a virtual destructor
> when you will be handling objects of a derived class through a pointer or
> reference whose static type is some base class, and in that case you will
> (nearly?) always need other virtual functions to provide the polymorphic
> interface that you'll use. The only exception I can imagine offhand
> would be if you were doing nothing but holding a bunch of them, as in a
> collection of some sort; but how could you ever do anything to the
> collected objects without virtual functions? Seems to me that the only
> thing you could do if they have no virtual function except the destructor
> is delete them, and if that's all you're doing... well, I suppose there
> could be some reason for deferring deletion for a bunch of mixed
> objects. It just doesn't seem real likely to me that that woudl be the
> ONLY action you'd want to take on them in a polymorphic fashion.
>
> But it's certainly legal to have only the destructor virtual.
You can do polymorphic things without any virtual functions. Casting a child
to a parent which has no virtual functions makes the class behave like it was
a class of that parent. You might want to delete it while it has been the
parent in a polymorphic sense. Thus, the destructor is the only virtual
function.
> > Is virtualness inherited by destructors? Does C++ automatically make all
> > applicable superclasses also have virtual destructor if they don't already?
>
> Is there any inheritance of anything from subclass to superclass? Or did
> you mean to write "subclass" there? Inheritance goes in only one
> direction: a class derived from a base class with a virtual destructor
> will have a virtual destructor. Deriving a class whose destructor is
> declared virtual from a base class with a non-virtual destructor doesn't
> magically change the base class in this respect (nor any other).
I did mean superclass when I said it. Based on what I've learned by thinking
about these things, I'm pretty convinced that all destructors should be
virtual all the time (implied). I can't find a single case where it would
make sense to destroy an object and not have all proper cleanup happen.
> dispatch. No magic, an object's actual type cannot affect anything done
> to it through a pointer or reference of a base type unless the operation
> is through a function that is virtual in that base type.
The thing that doesn't work for me is that the pointer type is
different, but it still has the same pointer value. At the low-level, you
are freeing the same block of memory either way. In order to
call a destructor, the system needs to convert the pointer to a class type
instance anyway.
Chris Parker
parker@cs.wpi.edu
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: matt@cyclops5.berkeley.edu (Matt Austern)
Date: 1995/11/10 Raw View
In article <199511091835.NAA11661@starling.WPI.EDU> Chris Parker <parker@owl.WPI.EDU> writes:
> I did mean superclass when I said it. Based on what I've learned by thinking
> about these things, I'm pretty convinced that all destructors should be
> virtual all the time (implied). I can't find a single case where it would
> make sense to destroy an object and not have all proper cleanup happen.
This falls into the category of "if you don't use it, you shouldn't
pay for it." A class that has virtual functions is more expensive
than a class that doesn't have any; in some cases that overhead can be
prohibitive.
So that's the case in which you want a non-virtual destructor: if the
extra overhead of virtual functions would be a problem, and if you
don't expect your class to be used as a base for inheritance, then you
shouldn't make the destructor virtual. This is reasonably common;
consider, for example, complex<double>. That's why the standard
allows non-virtual destructors.
It probably is true that if you have any virtual functions at all then
you should have a virtual destructor. Most compilers do issue
warnings if you have a polymorphic class without a virtual destructor.
--
Matt Austern He showed his lower teeth. "We
matt@physics.berkeley.edu all have flaws," he said, "and
http://dogbert.lbl.gov/~matt mine is being wicked."
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: bill@amber.ssd.hcsc.com (Bill Leonard)
Date: 1995/11/10 Raw View
In article <47u94u$4of@bigboote.WPI.EDU>, parker@WPI.EDU (Chris Parker) writes:
> May I inquire when you would ever *not* want the destructor to be virtual?
To save time and space. If there are no *other* virtual functions in the
class, then class objects need not contain a virtual function table
pointer, and access to a non-virtual destructor is faster.
The only time you *DO* need for a class to have a virtual destructor is
when you plan to delete objects of that class using a pointer or reference
to some base class. There are *many* classes for which that is not true,
especially when the classes otherwise have no virtual member functions.
> The only disadvantage of this is there is price to pay at runtime when
> freeing the object because we need to find the destructor function through
> dynamic binding. So, I propose that if that if at any point in a class
> heirarchy tree a destructor is declared virtual, all destructors in the tree
> are virtual because that is really what you are trying to ask for. What
> do you think?
This is virtually (sorry for the pun) impossible in your average C++
compilation environment. It would require the compiler to know about all
derived classes before it could generate code for any manipulation of a
given class object. Consider the following:
class A { A(); ~A(); }
A * a = Foo();
delete a; // Virtual or not?
Now if some other compilation unit somewhere is suddenly going to force A
to have a virtual destructor, the compiler must add a virtual function
table pointer to class A. Calls to class A's destructor, as in the "delete
a" above, cannot be completely compiled without global knowledge of all
classes derived from A.
Now all that is technically feasible, but is it desirable? Not in my
opinion. What problem are you solving by adding this requirement that
cannot be solved another way, say by making the destructors virtual
*explicitly* in the first place?
--
Bill Leonard
Harris Computer Systems Corporation
2101 W. Cypress Creek Road
Fort Lauderdale, FL 33309
Bill.Leonard@mail.hcsc.com
These opinions and statements are my own and do not necessarily reflect the
opinions or positions of Harris Computer Systems Corporation.
------------------------------------------------------------------------------
I feel like I've been sent for and couldn't go, and weren't needed after I
got there.
------------------------------------------------------------------------------
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: herbs@interlog.com (Herb Sutter)
Date: 1995/11/10 Raw View
In article <47u94u$4of@bigboote.WPI.EDU>, parker@WPI.EDU (Chris Parker) wrote:
>>>Is virtualness inherited by destructors? Does C++ automatically make all
>>>applicable superclasses also have virtual destructor if they don't already?
No.
> May I inquire when you would ever *not* want the destructor to be virtual?
Check out the FAQ under Question 75 (or thereabouts, the number may have
changed slightly since my version), Cline's FAQ book under Questions 98-99,
Scott Meyers' "Effective C++" (can't recall the section as I loaned the book
to someone), C++PL2 pg 216, D&E concidentally also pg 216, etc.
Short answer: When the class has no other virtual functions and you'll never
destroy derived objects through a base pointer.
(Related question: Should compilers warn you when you have a virtual function
but a non-virtual dtor? Answer: Not mandated, but encouraged as a "quality of
implementation" issue.)
>Probably only in the leaf of the class heirarchy. Destroying the object above
>the leaf child without having a virtual destructor causes nothing but a
>memory leak, and quite possibly pain and hardship.
That's an understatement. Two major problems besides a simple memory leak:
slicing and heap corruption, both of which break program correctness and are
murder to debug.
>So, I propose that if that if at any point in a class
>heirarchy tree a destructor is declared virtual, all destructors in the tree
>are virtual because that is really what you are trying to ask for. What do
>you think?
No. Say I have base B and derived D1 and D2. Only D2 has a virtual dtor.
Why should this imply that D1 ought to have one? Or even B for that matter,
if the D2 designer is anticipating further-derived objects will be accessed
through D2 pointers but knows B pointers aren't used or contemplated?
(If you think this discussion is interesting, read the FAQ about 'when should
operator= be virtual'.)
Herb
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184
Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/11/10 Raw View
parker@WPI.EDU (Chris Parker) wrote:
>Does C++ require you to declare your destructor virtual whenever you declare
>any other member function in the class to be virtual?
No. [The destructor will be virtual if and only if it is declared
as such OR a destructor of a direct or indirect base is declared
as such]
>Is it acceptable according to the standard
There is NO standard yet.
>for the destructor to be the only
>virtual member in the class?
Yes.
>Is virtualness inherited by destructors?
As above. (Yes :-)
>
>If virtualness of destructors is inherited, then what is supposed to happen to
>in the case where one of our subclasses uses multiple inheritance and one
>of the other trees leading to the subclass doesn't declare destructors to be
>virtual anywhere?
The derived class dtor is virtual.
What happens if you delete an object of a derived
type via a pointer to a base for which the destructor is NOT
virtual is not defined. So don't do it :-)
E.g. do NOT do:
struct Base {};
struct Derived : Base { int x; };
Base *b = new Derived;
delete b; // CRASH!!
Virtualness of the base dtor is required here to dispatch down to the
destructor of the most derived class, both to destroy the
complete object AND to deallocate the correct memory extent. Eg:
struct Base { virtual ~Base(){} };
struct Derived : Base { int x; };
Base *b = new Derived;
delete b; // OK!!
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/11/10 Raw View
martelli@cadlab.it (Alex Martelli) wrote:
>
>parker@WPI.EDU (Chris Parker) writes:
> ...
>If that subclass is destroyed through a pointer to an ancestor whose
>dtor isn't virtual, undefined behaviour (violation of a "shall").
No no! Undefined behaviour is NOT a violation.
Conformance applies to COMPILERS. When behaviour
is not defined, the compiler can produce code that
does anything, because there is no requirement
to satisfy.
So it's exactly the opposite of what you said:
where behaviour is undefined is the one place
it is IMPOSSIBLE for a "shall" to be violated,
because there isn't one :-)
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: herbs@interlog.com (Herb Sutter)
Date: 1995/11/10 Raw View
In article <199511100139.UAA11974@starling.WPI.EDU>,
Chris Parker <parker@owl.WPI.EDU> wrote:
> The thing that doesn't work for me is that the pointer type is
>different, but it still has the same pointer value. At the low-level, you
>are freeing the same block of memory either way. In order to
>call a destructor, the system needs to convert the pointer to a class type
>instance anyway.
I don't follow. To begin with, you certainly often do have different pointer
values for the same object depending on which base pointer(s) you use to
access it. Simple example: Base classes B1 and B2, derived class D from both
bases, and any D object will have a different pointer value when viewed
through a B1* and a B2*; a B1* points to the "B1 part" of the derived object
and a B2* points to the "B2 part" of the derived object.
If you fix that first sentence I think you'll see how to fix the rest too.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184
Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: martelli@cadlab.it (Alex Martelli)
Date: 1995/11/10 Raw View
parker@WPI.EDU (Chris Parker) writes:
...
> The only disadvantage of this is there is price to pay at runtime when
>freeing the object because we need to find the destructor function through
And a space cost that can be huge.
>dynamic binding. So, I propose that if that if at any point in a class
>heirarchy tree a destructor is declared virtual, all destructors in the tree
>are virtual because that is really what you are trying to ask for. What
>do you think?
Consider:
class Point {
unsigned short x, y;
public:
// nonvirtual methods
};
I want my compiler to stick that in 4 bytes and move it around in
registers, of course. Now, you want to make it carry the weight
of a _vptr_ *just in case* somebody does:
class VPoint: public Point {public: virtual ~VPoint();}
and
Point *p=new VPoint;
//...
dispose(p);
where "dispose(Point *)" is a function written and compiled far
in advance of anybody dreaming up VPoint, which at the end does
"delete p;"?
In other words, can the compiler, separately compiling dispose()
into a library-resident object before anybody ever inherited
from Point, "know" that Point's dtor is nonvirtual, or does it
have to fear that it can "change from under it" unexpectedly,
and therefore must always take a vptr from somewhere inside Point?
A pointer is 8 bytes on Alpha. Do you realize your proposal
may require a 200% space overhead on this class, or doing
without separate compilation altogether?
The philosophy of C++: if somebody does not use a feature, they
must pay no price whatsoever for the mere existence of that
feature. It can't be followed 100%, but it's a good guiding
principle, and IMHO it has served the language pretty well.
Alex
--
DISCLAIMER: these are TOTALLY personal opinions and viewpoints, NOT connected
in any way with my employer, nor any other organization or individual!
Email: martelli@cadlab.it Phone: +39 (51) 597313
CAD.LAB s.p.a., v. Ronzani 7/29, Casalecchio, Italia Fax: +39 (51) 597120
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: herbs@interlog.com (Herb Sutter)
Date: 1995/11/11 Raw View
In article <4805l3$hst@steel.interlog.com>, I wrote:
>> May I inquire when you would ever *not* want the destructor to be
virtual?
>
>Check out the FAQ under Question 75 (or thereabouts, the number may have
>changed slightly since my version), Cline's FAQ book under Questions 98-99,
>Scott Meyers' "Effective C++" (can't recall the section as I loaned the book
>to someone), C++PL2 pg 216, D&E concidentally also pg 216, etc.
I got off my duff and fetched the latest FAQ. It's number 79 now, not 75.
>Short answer: When the class has no other virtual functions and you'll never
>destroy derived objects through a base pointer.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184
Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: fjh@munta.cs.mu.OZ.AU (Fergus Henderson)
Date: 1995/11/12 Raw View
parker@WPI.EDU (Chris Parker) writes:
>Does C++ require you to declare your destructor virtual whenever you declare
>any other member function in the class to be virtual?
No. But it is a good idea to do so.
>Is it acceptable according to the standard for the destructor to be the only
>virtual member in the class?
Yes.
>Is virtualness inherited by destructors? Does C++ automatically make all
>applicable superclasses also have virtual destructor if they don't already?
Yes.
>If virtualness of destructors is inherited, then what is supposed to happen to
>in the case where one of our subclasses uses multiple inheritance and one
>of the other trees leading to the subclass doesn't declare destructors to be
>virtual anywhere?
I'm not sure I understand exactly what you are asking.
Could you be more specific (post code)?
--
Fergus Henderson WWW: http://www.cs.mu.oz.au/~fjh
fjh@cs.mu.oz.au PGP: finger fjh@128.250.37.3
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: martelli@cadlab.it (Alex Martelli)
Date: 1995/11/12 Raw View
John Max Skaller <maxtal@suphys.physics.su.oz.au> writes:
...
>>If that subclass is destroyed through a pointer to an ancestor whose
>>dtor isn't virtual, undefined behaviour (violation of a "shall").
>No no! Undefined behaviour is NOT a violation.
No, but if the _program_ violates a "shall", undefined behaviour
may result.
>where behaviour is undefined is the one place
>it is IMPOSSIBLE for a "shall" to be violated,
>because there isn't one :-)
5.3.5 verse 3 says "the static type shall have a virtual destructor or
the behaviour is undefined"; the two are _alternatives_, obviously
(mutually exclusive ones, too -- perhaps "or else" would be more
pedantically precise:-) -- and the undefined behaviour is due exactly
to the violation of the "shall", in that, if the "shall" were not
violated (by the program), then the undefined behaviour would not
obtain.
So, the undefined behaviour "is NOT a violation", but it can _follow_
from a violation on the program's part -- therefore, it's QUITE
possible for a "shall" to _have been_ violated (by the program)
where behaviour is (becomes) undefined.
Alex
--
DISCLAIMER: these are TOTALLY personal opinions and viewpoints, NOT connected
in any way with my employer, nor any other organization or individual!
Email: martelli@cadlab.it Phone: +39 (51) 597313
CAD.LAB s.p.a., v. Ronzani 7/29, Casalecchio, Italia Fax: +39 (51) 597120
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: John Max Skaller <maxtal@suphys.physics.su.oz.au>
Date: 1995/11/12 Raw View
Chris Parker <parker@owl.WPI.EDU> wrote:
>
>I did mean superclass when I said it. Based on what I've learned by thinking
>about these things, I'm pretty convinced that all destructors should be
>virtual all the time (implied). I can't find a single case where it would
>make sense to destroy an object and not have all proper cleanup happen.
Yes, but "safe cleanup" != "virtual destructor".
In particular, a single stand alone class such
as "complex" doesn't need a virtual destructor
because it is neither derived from nor is intended
to be a base of, another class.
Since on many systems virtual destructors
greatly increase the costs associated
with an object (size, dispatch efficiency, etc),
there's a performance reason (as well as the
obvious layout control reason) for not
coding a virtual destructor in a class.
{But I'm not disagreeing that in principle
all destructors should act as if virtual}
--
John Max Skaller voice: 61-2-566-2189
81 Glebe Point Rd fax: 61-2-660-0850
GLEBE NSW 2037 email: maxtal@suphys.physics.oz.au
AUSTRALIA email: skaller@maxtal.com.au
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: herbs@interlog.com (Herb Sutter)
Date: 1995/11/13 Raw View
In article <9531520.16333@mulga.cs.mu.OZ.AU>,
fjh@munta.cs.mu.OZ.AU (Fergus Henderson) wrote:
>>Is virtualness inherited by destructors? Does C++ automatically make all
>>applicable superclasses also have virtual destructor if they don't already?
>
>Yes.
No. :-) (I think he did mean "superclasses" (base classes), it wasn't a typo.
I missed this on first read too.)
[Moderator's note: oops, thanks for correcting me on that one.
The answer to the first question "Is virtualness inherited by
destructors?" is indeed "yes", but as you pointed out, the answer to
the second one is "no", since derived classes (subclasses) inherit
from base classes (superclasses), not vice versa. -fjh]
>>If virtualness of destructors is inherited, then what is supposed to happen
>>to in the case where one of our subclasses uses multiple inheritance and one
>>of the other trees leading to the subclass doesn't declare destructors to be
>>virtual anywhere?
>
>I'm not sure I understand exactly what you are asking.
>Could you be more specific (post code)?
He's talking about 'inheriting up' (making a base's dtor virtual if any
derived dtor is virtual) and so there is no answer because that's not C++.
However, it might help Chris if we answered a related question using
inheritance in the proper direction (down!):
struct Base1 { virtual ~Base1() {}; }
struct Base2 { ~Base2() {}; }
struct Derived : public Base1, public Base2 { ... };
This question is, Is Derived::~Derived() virtual, since one of the bases has a
virtual dtor and one doesn't? This answer is, Yes: 'once virtual, always
virtual' (in derived classes), just like with any virtual member function.
Herb
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Herb Sutter 2228 Urwin, Ste 102 voice (416) 618-0184
Connected Object Solutions Oakville ON Canada L6L 2T2 fax (905) 847-6019
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: wil@ittpub.nl
Date: 1995/11/13 Raw View
In article <MATT.95Nov10115356@cyclops5.berkeley.edu>
matt@cyclops5.berkeley.edu (Matt Austern) writes:
> In article <199511091835.NAA11661@starling.WPI.EDU> Chris Parker
> <parker@owl.WPI.EDU> writes:
>
> > I'm pretty convinced that all destructors should be virtual all the
> > time (implied). I can't find a single case where it would make sense
> > to destroy an object and not have all proper cleanup happen.
>
> [snip]
>
> if the extra overhead of virtual functions would be a problem, and if you
> don't expect your class to be used as a base for inheritance, then you
> shouldn't make the destructor virtual.
IMHO the famous non-virtual destructor pitfall is caused by a language
defect: currently, the language allows us to express that a member
function is virtual, but is does not provide us with a way of expressing
that a member function is non-virtual. Therefore, destructors can only be
non-virtual by default.
If we had a `nonvirtual' keyword, destructors could be made virtual by
default and we would have an escape mechanism for the case in which that
would result in an unacceptable overhead. As I tried to show on
comp.lang.c++ a few weeks ago, having a `nonvirtual' keyword could solve a
few others problems as well - but I believe the non-virtual destructor
pitfall is probably the most pressing one.
- Wil
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: wmooney@shl.com (William Mooney)
Date: 1995/11/13 Raw View
John Max Skaller <maxtal@suphys.physics.su.oz.au> says:
>
>Chris Parker <parker@owl.WPI.EDU> wrote:
>>
>>I did mean superclass when I said it. Based on what I've learned by thinking
>>about these things, I'm pretty convinced that all destructors should be
>>virtual all the time (implied). I can't find a single case where it would
>>make sense to destroy an object and not have all proper cleanup happen.
>
>Yes, but "safe cleanup" != "virtual destructor".
>In particular, a single stand alone class such
>as "complex" doesn't need a virtual destructor
>because it is neither derived from nor is intended
>to be a base of, another class.
>
>Since on many systems virtual destructors
>greatly increase the costs associated
>with an object (size, dispatch efficiency, etc),
>there's a performance reason (as well as the
>obvious layout control reason) for not
>coding a virtual destructor in a class.
>
>{But I'm not disagreeing that in principle
>all destructors should act as if virtual}
Hmmm, this really sounds like a case of "do I plan for reuse now, or
wait until I need to reuse and then double check all of my parent
classes" -- both approaches have their merits.
What you can do if the cost of virtual destructors on standalone
classes concerns you, yet you or someone else *may* derive from them
at some point in time, is to wrap the virtual keyword like so:
class A
{
A();
...
#if defined(STRICT_VIRTUAL)
virtual
#endif
~A();
...
};
As ugly as using proprecessor symbols can be at least this gets around
around the problem. Define STRICT_VIRTUAL in your header file before
including A.h and deriving from it. Then #undef STRICT_VIRTUAL when
you're done to implement on a case-by-case basis. Otherwise, put a
-DSTRICT_VIRTUAL on the compiler command line for all cases.
Bill
=============================================================================
William D. Mooney | email: wmooney@shl.com or 74353.1325@compuserve.com
| phone: 407.888.1829
SHL Systemhouse, Inc. | fax: 407.888.2259
=============================================================================
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]
Author: Dick Menninger <Dick.Menninger@daytonoh.attgis.com>
Date: 1995/11/13 Raw View
> ==========John Max Skaller, 11/10/95==========
>
>
> martelli@cadlab.it (Alex Martelli) wrote:
> >
> >parker@WPI.EDU (Chris Parker) writes:
> > ...
> >If that subclass is destroyed through a pointer to an ancestor whose
> >dtor isn't virtual, undefined behaviour (violation of a "shall").
>
>
> No no! Undefined behaviour is NOT a violation.
>
> Conformance applies to COMPILERS. When behaviour
> is not defined, the compiler can produce code that
> does anything, because there is no requirement
> to satisfy.
>
> So it's exactly the opposite of what you said:
> where behaviour is undefined is the one place
> it is IMPOSSIBLE for a "shall" to be violated,
> because there isn't one :-)
>
Actually, "undefined behavior" is a precisely
defined term in the WP, and not just a vague
common term. The meanings are constrained (1.3)
by text that starts "Permissible undefined behavior
ranges from" and then give three categories
of behavior that are permissible. The compiler
can ignore it and let the chips fall where they may.
The compiler can establish wierd responses
by making it part of the "environment" by
explicitly documenting that (a warning label
if you will). The compiler can terminate
translation or execution with a warning message.
In general, the application of this term to
situations by the committee is based on the
situation being potentially too hard to diagnose
in some of its manifestations.
There is a commonsense "shall" where these
situations are concerned. The programmer
shall avoid these situations like the plague
because the compiler will invariably do the first
of the three permissible behaviors and not help
detect it (Murphy's Law is they do not detect
your case, whatever it is).
Good Day
Dick
Dick.Menninger@DaytonOH.ATTGIS.COM
---
[ comp.std.c++ is moderated. Submission address: std-c++@ncar.ucar.edu.
Contact address: std-c++-request@ncar.ucar.edu. The moderation policy
is summarized in http://dogbert.lbl.gov/~matt/std-c++/policy.html. ]