Topic: Virtual destructors needed for inheritance
Author: Salters <msalters@lucent.com>
Date: 1999/06/02 Raw View
Christopher Eltschka wrote:
>
> Jerry Coffin wrote:
> >
> > In article <374AEFE8.5D91260A@sensor.com>, ron@sensor.com says...
> >
> > [ ... ]
> >
> > Change that from "pointer" to "pointer or reference".
>
> You cannot delete through a reference. If you only have a reference
> to the object, you must use the address-of operator to obtain a
> pointer to the same object. That is:
>
> class X {};
>
> X* p = new X;
> X& q = *new X;
>
> delete p; // Ok: p is a pointer
> delete q; // Error: q is not a pointer
> delete &q; // Ok: &q is a pointer
>
While that might not give undefined behavior from your compiler,
it is likely to give undefined behavior from whoever maintains
the coding standards at your place :-)
Seriously, I think that references do not carry ownership. Any
memory allocated by new should be pointed to by a (auto)pointer.
Ownership of the memory should never be an issue, so any pointer
that is used as a "owner" should always be a "owner".
That's why references in C++ are a good idea. If you want to call
a function by reference, you do not want that function to
(accidentally) delete its argument. For that you use a reference.
If you transfer ownership you will pass the pointer. If
ownership is always transferred by using pointers you will
never see delete &q. Strictly adhereing to this standard will
help prevent memory leaks. It is important to *not* use a pointer
type argument *unless* you take over ownership, to make sure
that the following code is clearly incorrect:
{
MyType local_automatic;
Obscure(&local_automatic) // Will take ownership
} // will call destructor of local_automatic, which it "doesn't own"
Using const cannot prevent deletion, as has been noted in this group
before. Of course, using auto_ptr is useful in this context, and
counted_ptr's are a solution with STL containers, but this is a
simple guideline I think belongs in coding standards.
Comments, anybody?
Michiel Salters
--
Michiel.Salters@cmg.nl
Consultant Software Engineering
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/05/27 Raw View
In article <374BE227.B97C4503@physik.tu-muenchen.de>,
celtschk@physik.tu-muenchen.de says...
[ ... ]
> You cannot delete through a reference.
One of these years I'm going to learn that I should be certain I'm
awake before I post.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/05/25 Raw View
In article <7hq7en$dcd$1@engnews1.eng.sun.com>,
clamage@eng.sun.com (Steve Clamage) wrote:
> Michael Greenberg <mgreenberg@scr.siemens.com> writes:
>
> >Ron Natalie wrote:
> >>
> >> The standard doesn't "require" virtual destructors under any
> >> conditions.
[snip]
>
> >That is incorrect. A virtual destructor is required anytime the
> >static type
> >of the object differs from the dynamic type.
>
> Natalie is correct. The standard does not require that the
> destructor be virtual.
I disagree - Ron Natalie stated that the Standard that does not ever
require a virtual destructor under *any* circumstances. That is not
true - there are specific circumstances where the Standard *does*
require a virtual destructor, i.e. when deleting an object through a
pointer to one of its base classes. In this situation, section 5.3.5(3)
states that the base class "shall have a virtual destructor or the
behaviour is undefined" - sounds like a requirement to me ;-)
[snip]
--
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post
here.
--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/05/25 Raw View
Jim Hyslop wrote:
>
> I disagree - Ron Natalie stated that the Standard that does not ever
> require a virtual destructor under *any* circumstances.
Let me reiterate (since people have been arguing over whether
I'm right or not).
A destructor needs to be declared virtual any time you call
delete on a derived object through a pointer to the base class.
It matters not (and this is what I got wrong) if the destructors
are trivial or implicitly generated according to the standard.
This is admittedly a silly restriction, but that's what the
standard says, so we're stuck with it.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jcoffin@taeus.com (Jerry Coffin)
Date: 1999/05/25 Raw View
In article <374AEFE8.5D91260A@sensor.com>, ron@sensor.com says...
[ ... ]
> A destructor needs to be declared virtual any time you call
> delete on a derived object through a pointer to the base class.
Change that from "pointer" to "pointer or reference".
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/05/26 Raw View
Stanley Friesen wrote:
>
> David R Tribble <dtribble@technologist.com> wrote:
>>
>> (or destructors at all). Bear in mind that if the base class doesn't
>> have any members that have destructors (such as being only ints
>> or PODs), or simply doesn't have any data members at all, then it
>> doesn't really need a destructor.
>
> Yes, but a *derived* class might be different in that respect, and it
> is in order to get the derived class destructor called that a base
> class destructor is declared virtual.
Yes; what I meant to write was that if none of the derived classes
that inherit the base class add any data members or virtual functions
(i.e., perhaps they only add static member variables or non-virtual
member functions), then the derived classes don't really need
destructors.
As I wrote earlier, it is easy to come up with an example class
hierarchy of POD structs that don't need destructors (or
constructors) at all. This is a fairly specialized use of
inheritance, and the trade-off of not having a fully inheritable
base class must be worth the benefit gained by allowing the classes
to be POD types. (It also assumes that you have control over the
whole inheritance hierarchy.)
For example:
struct NamedInt // a POD class type
{
char m_name[16+1];
int m_value;
bool toString(char *buf);
// compose a decimal string representation
};
struct NamedHex: public NamedInt
{
bool toString(char *buf);
// compose a hexadecimal string
};
struct NamedOct: public NamedInt
{
bool toString(char *buf);
// compose an octal string
};
The existence of such an example proves that it shouldn't always be
required to have a virtual destructor in the base class.
Unfortunately, this crosses the line into "undefined behavior"
territory as set forth in the standard.
void foo()
{
NamedInt * n = new NamedHex;
...
delete n; // undefined, ~NamedInt() not virtual
...
}
It would enlightening to know if any existing implementation has
a problem executing the above example.
-- David R. Tribble, dtribble@technologist.com --
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/26 Raw View
Jerry Coffin wrote:
>
> In article <374AEFE8.5D91260A@sensor.com>, ron@sensor.com says...
>
> [ ... ]
>
> > A destructor needs to be declared virtual any time you call
> > delete on a derived object through a pointer to the base class.
>
> Change that from "pointer" to "pointer or reference".
You cannot delete through a reference. If you only have a reference
to the object, you must use the address-of operator to obtain a
pointer to the same object. That is:
class X {};
X* p = new X;
X& q = *new X;
delete p; // Ok: p is a pointer
delete q; // Error: q is not a pointer
delete &q; // Ok: &q is a pointer
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Jim Hyslop <jim.hyslop@leitch.com>
Date: 1999/05/21 Raw View
In article <3740A9AB.603AA44F@vossnet.de>,
jbarfurth@vossnet.de wrote:
>
> Ron Natalie actually is correct.
Well, Michael painted a rather large stroke with his statement:
> Michael Greenberg wrote:
> > That is incorrect.
It is unclear whether Michael disagreed with the entire post made by
Ron, or with Ron's statement:
> > Ron Natalie wrote:
> > > The standard doesn't "require" virtual destructors under any
> > > conditions.
I obviously cannot speak for Michael, but I disagree with the
above-quoted portion of Ron's statement.
The Standard states that when the static and dynamic types of a pointer
being deleted are different, behaviour is undefined if the destructor is
not virtual. That sounds to me like the Standard is requiring a virtual
destructor under particular conditions.
[snip]
--
Jim
I ignore all email from recruitment agencies.
Please do not send me email with questions - post
here.
--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/05/21 Raw View
Zeisel Helmut wrote:
>
> In article <7hg5hk$noa$2@nntp4.atl.mindspring.net>, "Jonathan H Lundquist" <fluxsmith@fluxsmith.com> writes:
> >
> >I was quite surprised to read section 5.3.5 - 3 of the standard tonight. It
> >basically says if you publicly derive from a base class without a virtual
> >destructor, calling delete through a base class pointer (when the object is
> >actually of the derived class) is undefined behavior.
> >This seems to restrict the use of other's classes which have not been
> >designed with a virtual destructor needlessly. Prior to this my own view in
> >such cases has always been that if I there is no need to add any behavior to
> >the destructor not already provided by the base class destructor, then the
> >derivation is fine.
> >Can anyone shed some light on why this choice was made, rather than simply
> >saying if the destructor is not virtual in the static type that ony the
> >static type's destructor and its bases will be called.
> >
>
> Up to now I had the impression that it were save
> to have a base class without a virtual destructor and
> a derived class that adds only member functions and no data.
> As I see now, this is not allowed by the standard.
>
> Does anyone know whether real compilers make any difficulties
> in the case when only functions are added?
>
> In particular, I was experimenting with a class design
> where "copy-on-write" with proxy classes is replaced by
> a const base class and a derived class that adds the mutable part,
> say
>
> class A
> {
> friend class mutableA;
> public: // only constructor and const member functions...
> private: // data members
> };
>
> class mutableA: public A
> {
> public:
> // adds non-const member functions
> };
>
> The constructor A(const A&) just increases a reference count
> while A(const mutableA&) makes a deep copy and so on.
>
> I needed no virtual functions up to now;
> is it true that the standard requires a virtual destructor
> to be on the safe side,
> even though no real compiler really needs it?
A simple solution to be on the safe side could be to new and
delete only mutableA objects, and create A objects on stack only.
Of course a pointer or reference to A can still point/refer to
mutableA, but you can't delete through it. (Those advocating
no delete through const pointers will also tell you it's good
design not to allow deleting through A.)
I think the following should do:
class A
{
// ...
private:
void* operator new(size_t); // unimplemented
void operator delete(void*); // unimplemented
};
class mutableA:
public A
{
// ...
public:
void* operator new(size_t size) { return ::operator new(size); }
void operator delete(void* p) { ::operator delete(p); }
};
// example usage
int main()
{
mutableA* pmA = new mutableA;
A* pA = pmA;
delete pA; // Error: A::operator delete is private!
delete pmA; // Ok: mutableA::operator delete is public
A a; // Ok: no operator new or operator delete involved
}
Since you now cannot delete a pointer to A, but only a pointer
to mutableA, you should be safe.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/05/22 Raw View
Michael Greenberg <mgreenberg@scr.siemens.com> writes:
>Ron Natalie wrote:
>>
>> The standard doesn't "require" virtual destructors under any
>> conditions. Whether you want to use them is a matter of design.
>> Any time you have a derived class with a nontrivial destructor
>> (i.e., one who has no user defined destructor and whose members
>> and base classes have nontrivial destructors) and you want to
>> delete it through a base class pointer, you need to make the
>> base class destructor virtual.
>>
>That is incorrect. A virtual destructor is required anytime the static type
>of the object differs from the dynamic type.
Natalie is correct. The standard does not require that the
destructor be virtual. You can write useful programs with
well-defined behavior even when classes lack virtual destructors.
I can think of only one thing without well-defined behavior, and
that is your example.
>The behavior of the following is undefined:
>class foo {} ;
>class bar : public foo {} ;
>void xxx()
>{
> foo* f = new bar;
> delete f;
>}
Right. But if you don't delete an object via a pointer to a base
class, you don't run into this problem. Other uses of objects
are unaffected by the virtualness of the destructor. Static and
auto objects will be destroyed correctly. If you delete the bar
object via a bar* it will be destroyed correctly.
That said, you are asking for trouble if you don't make the
base-class destructor virtual, because someone might later write
code that depended on virtual destructors. A good guideline is
that any class that you intend to allow to be derived from should
have a virtual destructor. If you choose to ignore that guideline,
you should understand that you are trading away code stability and
flexibility. What you get in return should be worth the loss.
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: stanley@west.sun.com (Stanley Friesen [Contractor])
Date: 1999/05/19 Raw View
In article <374099B4.836D54E6@technologist.com>,
David R Tribble <dtribble@technologist.com> wrote:
>
>(or destructors at all). Bear in mind that if the base class doesn't
>have any members that have destructors (such as being only ints
>or PODs), or simply doesn't have any data members at all, then it
>doesn't really need a destructor.
Yes, but a *derived* class might be different in that respect, and it is
in order to get the derived class destructor called that a base class
destructor is declared virtual.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: zeisel@lnzx16.vai.co.at (Zeisel Helmut)
Date: 1999/05/17 Raw View
In article <7hg5hk$noa$2@nntp4.atl.mindspring.net>, "Jonathan H Lundquist" <fluxsmith@fluxsmith.com> writes:
>
>I was quite surprised to read section 5.3.5 - 3 of the standard tonight. It
>basically says if you publicly derive from a base class without a virtual
>destructor, calling delete through a base class pointer (when the object is
>actually of the derived class) is undefined behavior.
>This seems to restrict the use of other's classes which have not been
>designed with a virtual destructor needlessly. Prior to this my own view in
>such cases has always been that if I there is no need to add any behavior to
>the destructor not already provided by the base class destructor, then the
>derivation is fine.
>Can anyone shed some light on why this choice was made, rather than simply
>saying if the destructor is not virtual in the static type that ony the
>static type's destructor and its bases will be called.
>
Up to now I had the impression that it were save
to have a base class without a virtual destructor and
a derived class that adds only member functions and no data.
As I see now, this is not allowed by the standard.
Does anyone know whether real compilers make any difficulties
in the case when only functions are added?
In particular, I was experimenting with a class design
where "copy-on-write" with proxy classes is replaced by
a const base class and a derived class that adds the mutable part,
say
class A
{
friend class mutableA;
public: // only constructor and const member functions...
private: // data members
};
class mutableA: public A
{
public:
// adds non-const member functions
};
The constructor A(const A&) just increases a reference count
while A(const mutableA&) makes a deep copy and so on.
I needed no virtual functions up to now;
is it true that the standard requires a virtual destructor
to be on the safe side,
even though no real compiler really needs it?
Helmut
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: 1999/05/17 Raw View
Zeisel Helmut wrote:
>
> I needed no virtual functions up to now;
> is it true that the standard requires a virtual destructor
> to be on the safe side,
> even though no real compiler really needs it?
>
The standard doesn't "require" virtual destructors under any
conditions. Whether you want to use them is a matter of design.
Any time you have a derived class with a nontrivial destructor
(i.e., one who has no user defined destructor and whose members
and base classes have nontrivial destructors) and you want to
delete it through a base class pointer, you need to make the
base class destructor virtual.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Michael Greenberg <mgreenberg@scr.siemens.com>
Date: 1999/05/17 Raw View
That is incorrect. A virtual destructor is required anytime the static type
of the object differs from the dynamic type. The behavior of the following
is undefined:
class foo {} ;
class bar : public foo {} ;
void xxx()
{
foo* f = new bar;
delete f;
}
Ron Natalie wrote:
>
> The standard doesn't "require" virtual destructors under any
> conditions. Whether you want to use them is a matter of design.
> Any time you have a derived class with a nontrivial destructor
> (i.e., one who has no user defined destructor and whose members
> and base classes have nontrivial destructors) and you want to
> delete it through a base class pointer, you need to make the
> base class destructor virtual.
>
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: David R Tribble <dtribble@technologist.com>
Date: 1999/05/17 Raw View
Jonathan H Lundquist <fluxsmith@fluxsmith.com> writes
>> Can anyone shed some light on why this choice was made, rather than
>> simply saying if the destructor is not virtual in the static type
>> that ony the static type's destructor and its bases will be called.
Francis Glassborow wrote:
> Perhaps just that we should not require implementors to support bad
> coding practices (as the behaviour is undefined, an implementor is at
> liberty to define it for their implementation).
>
> I find it hard to imagine a publicly derived class that met good
> design principles for which a virtual destructor in the base class was
> inappropriate.
I can think of some specialized examples of single-inheritance
hierarchies of POD classes that don't require virtual destructors
(or destructors at all). Bear in mind that if the base class doesn't
have any members that have destructors (such as being only ints
or PODs), or simply doesn't have any data members at all, then it
doesn't really need a destructor.
Virtual destructors do carry a cost, which may not be appropriate
in every situation. It's obviously a question of what you're trying
to accomplish.
-- David R. Tribble, dtribble@technologist.com --
A little government and a little luck are necessary in life,
but only a fool trusts either of them.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Joerg Barfurth <jbarfurth@vossnet.de>
Date: 1999/05/17 Raw View
Ron Natalie actually is correct.
Michael Greenberg wrote:
>
> That is incorrect. A virtual destructor is required anytime the static type
> of the object differs from the dynamic type. The behavior of the following
> is undefined:
The behaviour of my code is not undefined. AND it uses public derivation with
no virtual dtors:
> class foo {} ;
> class bar : public foo {} ;
>
> void xxx()
> {
> foo* f = new bar;
bar *b = new bar;
> //delete f;
delete static_cast<bar*>(f);
delete b;
> }
Or simply
void xx()
{
bar autoB;
}
or
template<class T> void ttt();
void x()
{
ttt<bar>(); // will be safe unless ttt knows about class foo, and deletes
some T through a foo*.
}
It is a matter of design, whether objects of some class will ever be deleted
through pointers to base classes or even be dynamically allocated at all.
I sometimes have classes or whole class hierarchies) that are designed to be
used as template arguments. With these it is pretty safe to not have a virtual
destructor (unless the template requires a certain base class). It's just a
matter of compiletime polymorphism vs. runtime polymorphism then.
Thinking about that: Some standard library classes, that are intended as base
classes, don't have a virtual dtor (or any virtual functions). For example
look at std::binary_function<...>. Unless you delete a functor through a
pointer to that base class, you're fine. BTW: such a pointer would be pretty
much useless anyways.
> Ron Natalie wrote:
>
> >
> > The standard doesn't "require" virtual destructors under any
> > conditions. Whether you want to use them is a matter of design.
[snip]
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Jonathan H Lundquist" <fluxsmith@fluxsmith.com>
Date: 1999/05/18 Raw View
As someone else pointed out, I did fail to mention the additional criteria
which I always *thought* was required for it to be safe in my original post.
And that is that the derived type and the static type would have to be the
same size. If it were not for this language in the standard which makes it
undefined, I would say it's a real stretch to claim that deriving publicly
from a class which does not have a virtual destructor *only* to add to the
interface is bad design.
Francis Glassborow <francis@robinton.demon.co.uk> wrote in message
news:QtiBnPA2K+O3Ew1q@robinton.demon.co.uk...
>
> In article <7hg5hk$noa$2@nntp4.atl.mindspring.net>, Jonathan H Lundquist
> <fluxsmith@fluxsmith.com> writes
> >Can anyone shed some light on why this choice was made, rather than
simply
> >saying if the destructor is not virtual in the static type that ony the
> >static type's destructor and its bases will be called.
>
> Perhaps just that we should not require implementors to support bad
> coding practices (as the behaviour is undefined, an implementor is at
> liberty to define it for their implementation).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: jpotter@falcon.lhup.edu (John Potter)
Date: 1999/05/18 Raw View
scorp@btinternet.com (Dave Harris) wrote:
: fluxsmith@fluxsmith.com (Jonathan H Lundquist) wrote:
: > Can anyone shed some light on why this choice was made, rather than
: > simply saying if the destructor is not virtual in the static type
: > that ony the static type's destructor and its bases will be called.
: Here's my understanding. It only involves simple single inheritance:
: class A {
: int a;
: };
: class B : public A {
: int b;
: };
: We have sizeof(A) != sizeof(B). As I understand it, an implementation is
: allowed to use the type of delete's argument to decide the size of the
: object it is freeing.
: I know most implementations use a more general approach, often by defining
: new/delete in terms of malloc/free.
Yes/No. Also consider delete[] which was once delete[Iknow]. There
should be no reason for the user to remember the size.
Since delete() gets a void*, there is no way to decide the size of the
object as suggested. OTOH, the delete expression can decide on the
size of the deleted dereferenced pointer. Or, the virtual destructor
used could determine the size.
It must be static if there is no virtual destructor; otherwise, it
may be dynamic.
John
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: clamage@eng.sun.com (Steve Clamage)
Date: 1999/05/18 Raw View
zeisel@lnzx16.vai.co.at (Zeisel Helmut) writes:
>Up to now I had the impression that it were safe
>to have a base class without a virtual destructor and
>a derived class that adds only member functions and no data.
>As I see now, this is not allowed by the standard.
>Does anyone know whether real compilers make any difficulties
>in the case when only functions are added?
You get into difficulties only if an object is allocated on
the heap and deleted via a pointer to a base class.
Instead of trying to enumerate cases where it is safe or unsafe,
the standard just says the results are undefined. An implementation
is always allowed to provide defined behavior, but you just can't
rely on code working everywhere.
Other articles in this thread have pointed out why the behavior
is in general unpredictable.
Now suppose that you have been careful never to allocate the
objects on the heap; all objects are static or auto. Or maybe
the destructors are trivial or your derived class adds only
non-virtual functions and in your implementation you don't get
into trouble deleting a derived object via a pointer to the
base type. (But what will happen when you port your code to
another compiler, or upgrade your existing compiler?)
Someone else might see you have a hierarchy and derive additional
classes -- but not understand the restrictions that apply to
the hierarchy.
In short, you have to consider the potential bad effects of not
declaring a virtual destructor, and weigh them against the
benefits you expect to get from the design shortcut (non-virtual
base-class destructor).
--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Ewert_Ahr._Electronic_GmbH@t-online.de (Gernot)
Date: 1999/05/18 Raw View
Zeisel Helmut wrote:
> In particular, I was experimenting with a class design
> where "copy-on-write" with proxy classes is replaced by
> a const base class and a derived class that adds the mutable part,
> say
>
> class A
> {
> friend class mutableA;
> public: // only constructor and const member functions...
> private: // data members
> };
>
> class mutableA: public A
> {
> public:
> // adds non-const member functions
> };
>
> The constructor A(const A&) just increases a reference count
> while A(const mutableA&) makes a deep copy and so on.
>
I have done exactly the same thing (BTW, it proves to be extremly
handy!) and found no problems. If you delete an object of your class
"mutableA" with a pointer to the base class "A", the non-virtual base
class destructor is called, which is totally sufficient for this
application. (No need to remind me that this is "non-standard", please!)
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "Jonathan H Lundquist" <fluxsmith@fluxsmith.com>
Date: 1999/05/14 Raw View
I was quite surprised to read section 5.3.5 - 3 of the standard tonight. It
basically says if you publicly derive from a base class without a virtual
destructor, calling delete through a base class pointer (when the object is
actually of the derived class) is undefined behavior.
This seems to restrict the use of other's classes which have not been
designed with a virtual destructor needlessly. Prior to this my own view in
such cases has always been that if I there is no need to add any behavior to
the destructor not already provided by the base class destructor, then the
derivation is fine.
Can anyone shed some light on why this choice was made, rather than simply
saying if the destructor is not virtual in the static type that ony the
static type's destructor and its bases will be called.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/05/14 Raw View
In article <7hg5hk$noa$2@nntp4.atl.mindspring.net>, Jonathan H Lundquist
<fluxsmith@fluxsmith.com> writes
>Can anyone shed some light on why this choice was made, rather than simply
>saying if the destructor is not virtual in the static type that ony the
>static type's destructor and its bases will be called.
Perhaps just that we should not require implementors to support bad
coding practices (as the behaviour is undefined, an implementor is at
liberty to define it for their implementation).
I find it hard to imagine a publicly derived class that met good design
principles for which a virtual destructor in the base class was
inappropriate. With the standard written the way it is, if some
careless programmer uses inheritance for modification or enhancement
from a base class that was not overtly designed to meet public
derivation criteria the consequences are of their own making. If you
already own the base class adding virtual ~MyType(){} to its interface
is hardly a back-breaking task.
Francis Glassborow Journal Editor, Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: "John Hickin" <hickin@nortelnetworks.com>
Date: 1999/05/14 Raw View
Jonathan H Lundquist wrote:
>
> I was quite surprised to read section 5.3.5 - 3 of the standard tonight. It
> basically says if you publicly derive from a base class without a virtual
It is essentially to avoid core dumps. The easiest example by which I
can illustrate this is through the use of multiple inheritance:
class D : public B1 , public B2 { ... };
No matter how an implementation lays out a D, at least one of the
sub-components B1 and B2, will have an address that differs from that of
D. WLG assume that it is B2. To delete a new D through a B2 pointer
requires B2 to have a virtual destructor so that the B2 pointer may be
converted back into a D pointer before operator delete() is called to
free up the memory.
Another useful source of core dumps is when a virtual base class has no
virtual destructor and you delete through a pointer to the virtual base.
> Can anyone shed some light on why this choice was made, rather than simply
> saying if the destructor is not virtual in the static type that ony the
> static type's destructor and its bases will be called.
>
If you allowed operator delete() to be called you would invote core
dumps as noted above. If you bypassed it there would be a memory leak.
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: nimel@my-dejanews.com
Date: 1999/05/14 Raw View
In article <7hg5hk$noa$2@nntp4.atl.mindspring.net>,
"Jonathan H Lundquist" <fluxsmith@fluxsmith.com> wrote:
[...]
> Can anyone shed some light on why this choice was made, rather than
> simply saying if the destructor is not virtual in the static type
> that ony the static type's destructor and its bases will be called.
I read your question as: Why did the standard commitee decide that
delete baseClassPointer is undefined behaviour, rather than just
state that destructors of derived classes will not be called when
there is no virtual destructor.
I think it is quite obvious. Consider the following code:
struct A
{
int a1;
};
struct B
{
int b1;
};
struct C : A, B
{
int c1;
};
int main()
{
C* c = new C;
A* a = c;
B* b = c;
delete b; // Problem (undefined behaviour)
}
On a typical implementation either a or b will point to a different
address than c. The call to delete will return the memory owned by
the object to the memory management system. Since there is no
virtual table in B there is no way for the compiler to find out the
objects actual address within the delete function, so a different
address is returned than the one that was aquired by the call to
new C.
/Niklas Mellin
--== Sent via Deja.com http://www.deja.com/ ==--
---Share what you know. Learn what you don't.---
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]
Author: scorp@btinternet.com (Dave Harris)
Date: 1999/05/14 Raw View
fluxsmith@fluxsmith.com (Jonathan H Lundquist) wrote:
> Can anyone shed some light on why this choice was made, rather than
> simply saying if the destructor is not virtual in the static type
> that ony the static type's destructor and its bases will be called.
Here's my understanding. It only involves simple single inheritance:
class A {
int a;
};
class B : public A {
int b;
};
We have sizeof(A) != sizeof(B). As I understand it, an implementation is
allowed to use the type of delete's argument to decide the size of the
object it is freeing.
I know most implementations use a more general approach, often by defining
new/delete in terms of malloc/free. Many of them store the size of each
object in a hidden word just before the object. However, that incurs a
space overhead - it could double the memory needed for a small object like
A. Using the argument's type avoids the overhead.
With this scheme, subclasses can be dealt with only if the base class has
a virtual function; you can store the size in the vtable. With no virtual
functions, there is no vtable. If the implementation uses the argument's
static type and the dynamic type is different, the size will be wrong and
heap corruption may result. The standard is saying this is OK.
Implementations don't have to deal with mismatched new/delete for
non-virtual classes.
The cost is that we have to track the dynamic type of non-virtual objects
ourselves. This is a small price to pay for doubling the memory
efficiency. You can always add a virtual destructor if it's inconvenient.
Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
brangdon@cix.co.uk | And close your eyes with holy dread,
| For he on honey dew hath fed
http://www.bhresearch.co.uk/ | And drunk the milk of Paradise."
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]