469,923 Members | 1,688 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 469,923 developers. It's quick & easy.

Virtual destructor

When i compile my program with the -ansi -Wall -pedantic
flags,
i get this warning: `class vechile' has virtual functions
but non-virtual destructor, and the same with my
sub-classes. But when i add a virtual destructor like this :

" virtual ~vechile". I get this error:
Undefined first referenced
symbol in file
vtable for vechile /var/tmp//ccC9yD6Z.o
ld: fatal: Symbol referencing errors. No output written to
a.out
collect2: ld returned 1 exit status
Can anyone help me?

Oct 5 '05 #1
26 3670
Ian
pmizzi wrote:
When i compile my program with the -ansi -Wall -pedantic
flags,
i get this warning: `class vechile' has virtual functions
but non-virtual destructor, and the same with my
sub-classes. But when i add a virtual destructor like this :

" virtual ~vechile". I get this error:


You haven't provides a body for the destructor. If it does nothing ,
then ~vechile() {} will suffice.

Ian
Oct 5 '05 #2
pmizzi wrote:
When I compile my program with the -ansi -Wall -pedantic flags,
I get this warning: `class vechile' has virtual functions
but non-virtual destructor,
It's a warning. Ignore it.
and the same with my sub-classes.
But, when I add a virtual destructor like this:

"virtual ~vechile", I get this error:

Undefined first referenced
symbol in file
vtable for vechile /var/tmp//ccC9yD6Z.o
ld: fatal: Symbol referencing errors. No output written to
a.out
collect2: ld returned 1 exit status

Can anyone help me?


Don't define a virtual destructor if you don't need one.
If you really need a virtual destructor,
you will need virtual constructors as well.
No function should ever delete an object
that was allocated by the calling function and,
in C++, it is poor programming practice
to require the calling program
to explicitly delete an object through a pointer
returned by a function that allocated the object.
Oct 5 '05 #3
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message
news:di**********@nntp1.jpl.nasa.gov...
pmizzi wrote:
When I compile my program with the -ansi -Wall -pedantic flags,
I get this warning: `class vechile' has virtual functions
but non-virtual destructor,
It's a warning. Ignore it.


It is a warning that should not be ignored in almost all cases. A virtualy
destructor is only rarely unnecessary. Even then, not defining virtual would
be a timebomb.

Deleting a polymorphic object through a base class pointer is very common.
It is undefined behavior when the destructor is non-virtual in that case.
and the same with my sub-classes.
But, when I add a virtual destructor like this:

"virtual ~vechile", I get this error:

Undefined first referenced
symbol in file
vtable for vechile /var/tmp//ccC9yD6Z.o
ld: fatal: Symbol referencing errors. No output written to
a.out
collect2: ld returned 1 exit status

Can anyone help me?


Don't define a virtual destructor if you don't need one.


That is very rarely the case.
If you really need a virtual destructor,
you will need virtual constructors as well.
Not at all. Using a function to make the decision on what object to
construct and to return a base object pointer is very common:

Base * read_object(/* ... */)
{
/* ... */
return some_condition
? new Derived1
: new Derived2;
}

/* ... */

Base * base = read_object(/* ... */);
No function should ever delete an object
that was allocated by the calling function
I can think of a linked-list implementation that has a function, which
removes objects. Surely the objects would not be allocated in that function,
yet deleted in there.
and,
in C++, it is poor programming practice
to require the calling program
to explicitly delete an object through a pointer
returned by a function that allocated the object.


See the read_object function above. How do you propose we delete the
returned object? Of course approach is to return a suitable smart pointer
that communicates precisely the transfer of ownership, which in turn means
that the object will be deleted outside of the allocating function.

Ali

Oct 5 '05 #4
Ali Çehreli wrote:
E. Robert Tisdale wrote:
If you really need a virtual destructor,
you will need virtual constructors as well.


Not at all. Using a function to make the decision on what object to
construct and to return a base object pointer is very common:

Base* read_object(/* ... */) {
/* ... */
return some_condition? new Derived1: new Derived2;
}

/* ... */

Base* base = read_object(/* ... */);


But it isn't good programming practice in C++.
Your program already knows about types Derived1 and Derived2
so you might as well use them in the calling program.

A virtual constructor is more "extensible".
See Bjarne Stroustrup, "The C++ Programming Language: Third Edition",
Chapter 15: Class Hierarchies, Section 6: Free Store,
Subsection 2: Virtual constructors, pages 424-5.
Oct 5 '05 #5
"E. Robert Tisdale" <E.**************@jpl.nasa.gov> wrote in message
news:di*********@nntp1.jpl.nasa.gov...
Ali Çehreli wrote:
E. Robert Tisdale wrote:
If you really need a virtual destructor,
you will need virtual constructors as well.
Not at all. Using a function to make the decision on what object to
construct and to return a base object pointer is very common:

Base* read_object(/* ... */) {
/* ... */
return some_condition? new Derived1: new Derived2;
}

/* ... */

Base* base = read_object(/* ... */);


But it isn't good programming practice in C++.


Himmm... I don't see what you mean.

Even Stroustrup refers to such a use in C++ in the pages you quoted. My
read_object does exactly the same thing as his Ival_maker::dial does. Maybe
naming it as "factory method" might
Your program already knows about types Derived1 and Derived2
so you might as well use them in the calling program.
My program knows of them, but the translation unit does not know of them. We
don't always mention the physical structure of code in our posts, but you
can assume that the declaration is

Base * read_object(/* ... */);

and the user is

Base * base = read_object(/* ... */);

So, Derived1 and Derived2 are know only in another translation unit, where
read_object is defined.
A virtual constructor is more "extensible".
It is not more extensible than a function like read_object; you can extend
read_object any way we like. Besides, their application are very different:
read_object returns a brand new object, virtual constructor copies an
existing object. That's why I use virtual constructor in some of my copy
constructors.
See Bjarne Stroustrup, "The C++ Programming Language: Third Edition",
Chapter 15: Class Hierarchies, Section 6: Free Store,
Subsection 2: Virtual constructors, pages 424-5.


Thanks for the refence; I've re-read it. I think he could declare new_expr
as a static member function. Then it could be used without an existing
object; esentially using the same principle as a simple function as
read_object above.

Ali

Oct 5 '05 #6
Ali Çehreli wrote:
E. Robert Tisdale wrote:
A virtual constructor is more "extensible".
It is not more extensible than a function like read_object;
you can extend read_object any way we like.
Besides, their application are very different:
read_object returns a brand new object,
virtual constructor copies an existing object.
That's why I use virtual constructor in some of my copy constructors.
See Bjarne Stroustrup, "The C++ Programming Language: Third Edition",
Chapter 15: Class Hierarchies, Section 6: Free Store,
Subsection 2: Virtual constructors, pages 424-5.


Stoustrup's example shows a virtual "default constructor" (new_expr)
and a virtual "copy constructor" (clone) corresponding to
the actual constructors for class Expr.
Thanks for the refence; I've re-read it.
I think he could declare new_expr as a static member function.
Then it could be used without an existing object;
esentially using the same principle
as a simple function as read_object above.


That means that the base class would need to know about
all of the derived types which are, generally, unknown
when the base class is implemented.
Oct 6 '05 #7
On Wed, 05 Oct 2005 09:03:33 -0700, "E. Robert Tisdale"
<E.**************@jpl.nasa.gov> wrote:
pmizzi wrote:
When I compile my program with the -ansi -Wall -pedantic flags,
I get this warning: `class vechile' has virtual functions
but non-virtual destructor,
It's a warning. Ignore it.


Famous last words. Warnings should be dealt with, or at least documented,
because they indicate an error-prone construct.

Destructors should almost always be declared virtual. Without virtual
destructors derived classes stand a good chance of not getting destroyed
correctly.
If you really need a virtual destructor,
you will need virtual constructors as well.
Virtual destructors and "virtual constructors" (vis-a-vis Stroustroup) solve
very different problems. Don't confuse them with each other.
No function should ever delete an object
that was allocated by the calling function and,
in C++, it is poor programming practice
to require the calling program
to explicitly delete an object through a pointer
returned by a function that allocated the object.


Nonsense. std::auto_ptr uses that idiom.

There are situations where an Orchestrator may construct an object on the heap
derived from some base class, then passes a reference to that object on the
heap to a helper object as a reference to the base class. The helper object
then "owns" and manages that object, and will destruct it on its own schedule.

There's nothing wrong with that pattern.

-dr
Oct 6 '05 #8
In message <di*********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
Ali Çehreli wrote:
E. Robert Tisdale wrote:
If you really need a virtual destructor,
you will need virtual constructors as well. Not at all. Using a function to make the decision on what object to
construct and to return a base object pointer is very common:
Base* read_object(/* ... */) {
/* ... */
return some_condition? new Derived1: new Derived2;
}
/* ... */
Base* base = read_object(/* ... */);


But it isn't good programming practice in C++.
Your program already knows about types Derived1 and Derived2
so you might as well use them in the calling program.


So virtual functions are a waste of time. You heard it here first,
folks!

A virtual constructor is more "extensible".
See Bjarne Stroustrup, "The C++ Programming Language: Third Edition",
Chapter 15: Class Hierarchies, Section 6: Free Store,
Subsection 2: Virtual constructors, pages 424-5.


--
Richard Herring
Oct 6 '05 #9
In message <di**********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
pmizzi wrote:
When I compile my program with the -ansi -Wall -pedantic flags,
I get this warning: `class vechile' has virtual functions
but non-virtual destructor,
It's a warning. Ignore it.
and the same with my sub-classes.
But, when I add a virtual destructor like this:
"virtual ~vechile", I get this error:

Undefined first referenced
symbol in file
vtable for vechile /var/tmp//ccC9yD6Z.o
ld: fatal: Symbol referencing errors. No output written to
a.out
collect2: ld returned 1 exit status
Can anyone help me?


Don't define a virtual destructor if you don't need one.
If you really need a virtual destructor,
you will need virtual constructors as well.


Nonsense. They aren't paired requirements.
No function should ever delete an object
that was allocated by the calling function
ITYM "programs using pointers need a consistent, well-defined ownership
model"
and,
in C++, it is poor programming practice
to require the calling program
to explicitly delete an object through a pointer
returned by a function that allocated the object.


If the caller doesn't delete the object, what does, and how would it
obviate the need for a virtual dtor?

You've just condemned many kinds of smart pointer, garbage collection,
factory patterns, and much more, as "poor programming practice."

Personally I shall continue to use them whenever it's appropriate.

--
Richard Herring
Oct 6 '05 #10
Dave Rahardja wrote:
E. Robert Tisdale wrote:
pmizzi wrote:
When I compile my program with the -ansi -Wall -pedantic flags,
I get this warning: `class vechile' has virtual functions
but non-virtual destructor,
It's a warning. Ignore it.


Famous last words. Warnings should be dealt with, or at least documented,
because they indicate an error-prone construct.


Not necessarily. Like lint:

http://wombat.doc.ic.ac.uk/foldoc/fo...&action=Search

most modern C++ compilers will warn you
about perfectly acceptable constructs
that might contain errors:
cat f.cc void f(void) {
int a[2][2] = { 0, 1, 2, 3 };
}
g++ -Wall -ansi -pedantic -c f.cc f.cc: In function ‘void f()’:
f.cc:2: warning: missing braces around initializer
f.cc:2: warning: unused variable ‘a’
Destructors should almost always be declared virtual.
Without virtual destructors,
derived classes stand a good chance of not getting destroyed correctly.
How?
If you really need a virtual destructor,
you will need virtual constructors as well.


Virtual destructors and "virtual constructors" (vis-a-vis Stroustroup) solve
very different problems. Don't confuse them with each other.
No function should ever delete an object
that was allocated by the calling function and,
in C++, it is poor programming practice
to require the calling program
to explicitly delete an object through a pointer
returned by a function that allocated the object.


Nonsense. std::auto_ptr uses that idiom.

There are situations where an Orchestrator may construct an object on the heap
derived from some base class, then passes a reference to that object on the
heap to a helper object as a reference to the base class. The helper object
then "owns" and manages that object, and will destruct it on its own schedule.


Please show us an example.
There's nothing wrong with that pattern.


Except that it is error prone.
Oct 6 '05 #11
Richard Herring wrote:
Personally I shall continue to use them whenever it's appropriate.


Unfortunately, you will continue to use them
whether they are appropriate or not
because you don't know when they are appropriate
and when they are not appropriate.
Oct 6 '05 #12
Dave Rahardja wrote:
Destructors should almost always be declared virtual.
Without virtual destructors,
derived classes stand a good chance of not getting destroyed correctly.

E. Robert Tisdale <E.**************@jpl.nasa.gov> wrote: How?


How about:
#include <iostream>

class Base
{
public:
Base() : base_data(new int[5]) { std::cout << "B()\n"; }
~Base() { std::cout << "~B()\n"; delete [] base_data; }
protected:
int* base_data;
};

class Derived : public Base
{
public:
Derived() : derived_data(new int[6]) { std::cout << "D()\n"; }
~Derived() { std::cout << "~D()\n"; delete [] derived_data; }
protected:
int* derived_data;
};

int main()
{
Base* b = new Derived;
delete b;

return 0;
}
Output is:
B()
D()
~B()

which says that the derived class's destructor does not get called, thus
derived_data does not get destroyed properly.

--
Marcus Kwok
Oct 6 '05 #13
Marcus Kwok wrote:
Dave Rahardja wrote:
Destructors should almost always be declared virtual.
Without virtual destructors,
derived classes stand a good chance of not getting destroyed correctly.

E. Robert Tisdale wrote:
How?


How about:

#include <iostream>

class Base {
public:
Base(void): base_data(new int[5]) { std::cout << "B(void)\n"; }
~Base(void) { std::cout << "~B(void)\n"; delete [] base_data; }
protected:
int* base_data;
};

class Derived: public Base {
public:
Derived(void): derived_data(new int[6]) { std::cout << "D(void)\n"; }
~Derived(void) { std::cout << "~D(void)\n"; delete [] derived_data; }
protected:
int* derived_data;
};

int main(int argc, char* argv[]) {
Base* b = new Derived;
delete b;
return 0;
}

Output is:

B(void)
D(void)
~B(void)

which says that the derived class's destructor does not get called,
thus derived_data does not get destroyed properly.


That's just a bad example.
The programmer (you) did something stupid and unnecessary.
How about:
cat main.cc #include <iostream>

class Base {
protected:
int* base_data;
public:
Base(void): base_data(new int[5]) {
std::cout << "B(void)" << std::endl; }
~Base(void) {
std::cout << "~B(void)" << std::endl;
delete [] base_data; }
};

class Derived: public Base {
protected:
int* derived_data;
public:
Derived(void) : derived_data(new int[6]) {
std::cout << "D(void)" << std::endl; }
~Derived(void) {
std::cout << "~D(void)" << std::endl;
delete [] derived_data; }
};

int main(int argc, char* argv[]) {
Derived* d = new Derived;
delete d;
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main

B(void)
D(void)
~D(void)
~B(void)

But, of course, allocation from free store was unnecessary.
You should have substituted:

int main(int argc, char* argv[]) {
Derived d;
return 0;
}

C++ is *not* Java.
You don't have a garbage collector to clean up after you.
This means that you should avoid allocating free storage explicity
and use automatic storage instead.
If you find yourself in a situation
where you *must* allocate free storage
(you have not shown us such a case yet),
then you must be more careful about how you do it.
An unnecessary virtual destructor might be *very* expensive
if your C++ compiler cannot optimize it away.
Oct 6 '05 #14
E. Robert Tisdale <E.**************@jpl.nasa.gov> wrote:
That's just a bad example.
The programmer (you) did something stupid and unnecessary.
What is stupid about using a base pointer to point to a derived type? I
hear it's pretty common when using polymorphism.
How about:
> cat main.cc #include <iostream>

class Base {
protected:
int* base_data;
public:
Base(void): base_data(new int[5]) {
std::cout << "B(void)" << std::endl; }
~Base(void) {
std::cout << "~B(void)" << std::endl;
delete [] base_data; }
};

class Derived: public Base {
protected:
int* derived_data;
public:
Derived(void) : derived_data(new int[6]) {
std::cout << "D(void)" << std::endl; }
~Derived(void) {
std::cout << "~D(void)" << std::endl;
delete [] derived_data; }
};

int main(int argc, char* argv[]) {
Derived* d = new Derived;
delete d;
return 0;
}
> g++ -Wall -ansi -pedantic -o main main.cc
> ./main

B(void)
D(void)
~D(void)
~B(void)
But, of course, allocation from free store was unnecessary.
You should have substituted:

int main(int argc, char* argv[]) {
Derived d;
return 0;
}


I just posted a minimal example demonstating the problem. What if the
class had a lot of data, and we needed a lot of objects of this type,
such that automatic variables are larger than the available stack space?
C++ is *not* Java.
I never said it was.
You don't have a garbage collector to clean up after you.
This means that you should avoid allocating free storage explicity
and use automatic storage instead.
If you find yourself in a situation
where you *must* allocate free storage
(you have not shown us such a case yet),
then you must be more careful about how you do it.
If you correctly implement RAII then it becomes less of an issue.
An unnecessary virtual destructor might be *very* expensive
if your C++ compiler cannot optimize it away.


--
Marcus Kwok
Oct 6 '05 #15
Marcus Kwok wrote:
E. Robert Tisdale wrote:
That's just a bad example.
The programmer (you) did something stupid and unnecessary.


What is stupid about using a base pointer to point to a derived type?
I hear it's pretty common when using polymorphism.


But you weren't "using polymorphism".
The object's actual type was known in the scope where you deleted it.
You might as well write:

void* p = (void*)(new Derived);

if you are going to conceal the objects actual type.
(I'm not kidding.
Some C programmers actually write "object oriented" code this way.)
Oct 6 '05 #16
Marcus Kwok wrote:
What is stupid about using a base pointer to point to a derived type?
I hear it's pretty common when using polymorphism.

E. Robert Tisdale <E.**************@jpl.nasa.gov> wrote: But you weren't "using polymorphism".


Yes, I know, but I was just demonstrating the problem with not having a
virtual destructor. I think you are missing the bigger picture.
There's even a FAQ about it.

FAQ entry:
http://www.parashift.com/c++-faq-lit....html#faq-20.7

When should my destructor be virtual?
When someone will delete a derived-class object via a base-class
pointer.

In particular, here's when you need to make your destructor virtual:

* if someone will derive from your class,

* and if someone will say new Derived, where Derived is derived from
your class,

* and if someone will say delete p, where the actual object's type
is Derived but the pointer p's type is your class.

Confused? Here's a simplified rule of thumb that usually protects you
and usually doesn't cost you anything: make your destructor virtual if
your class has any virtual functions. Rationale:

* that usually protects you because most base classes have at least
one virtual function.

* that usually doesn't cost you anything because there is no added
per-object space-cost for the second or subsequent virtual in your
class. In other words, you've already paid all the per-object
space-cost that you'll ever pay once you add the first virtual
function, so the virtual destructor doesn't add any additional
per-object space cost. (Everything in this bullet is
theoretically compiler-specific, but in practice it will be valid
on almost all compilers.)

Note: if your base class has a virtual destructor, then your destructor
is automatically virtual. You might need an explicit destructor for
other reasons, but there's no need to redeclare a destructor simply to
make sure it is virtual. No matter whether you declare it with the
virtual keyword, declare it without the virtual keyword, or don't
declare it at all, it's still virtual.

BTW, if you're interested, here are the mechanical details of why you
need a virtual destructor when someone says delete using a Base pointer
that's pointing at a Derived object. When you say delete p, and the
class of p has a virtual destructor, the destructor that gets invoked is
the one associated with the type of the object *p, not necessarily the
one associated with the type of the pointer. This is A Good Thing. In
fact, violating that rule makes your program undefined. The technical
term for that is, "Yuck."

--
Marcus Kwok
Oct 6 '05 #17
"E. Robert Tisdale" wrote:

Marcus Kwok wrote:
E. Robert Tisdale wrote:
That's just a bad example.
The programmer (you) did something stupid and unnecessary.


What is stupid about using a base pointer to point to a derived type?
I hear it's pretty common when using polymorphism.


But you weren't "using polymorphism".


Granted, but he easily could have:

int main()
{
std::vector< Base* > Objects;

for( int i = 0; i < 10; ++i ) {
std::cout << "What Object do you want ? (0 = Base, 1 = Derived) ";
int Type;
std::cin >> Type;
switch( Type ) {
case 0:
Objects.push_back( new Base );
break;
case 1:
Objects.push_back( new Derived );
break;
}
}

// do whatever you want to do with Objects.

for( int i = 0; i < 10; ++i )
Objects[i].foo();

// Get rid of them.

for( int i = 0; i < 10; ++i )
delete Objects[i];
}

No changes are required for Base and Derived (other then adding
a virtual foo function, but this was not the issue at hand which
turned around virtual dstructors and virtual constructors).
Yet the program works correctly (for a correct user input.) For this
it needs a virtual destructor and no virtual constructor.

--
Karl Heinz Buchegger
kb******@gascad.at
Oct 7 '05 #18
In message <di**********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
Richard Herring wrote:
[I note that you don't care to address my substantive comments]
Personally I shall continue to use them whenever it's appropriate.


Unfortunately, you will continue to use them
whether they are appropriate or not
because you don't know when they are appropriate
and when they are not appropriate.


Your mind-reading skills need work, too.

--
Richard Herring
Oct 7 '05 #19
In message <di**********@nntp1.jpl.nasa.gov>, E. Robert Tisdale
<E.**************@jpl.nasa.gov> writes
Marcus Kwok wrote:
E. Robert Tisdale wrote:
That's just a bad example.
The programmer (you) did something stupid and unnecessary. What is stupid about using a base pointer to point to a derived
type?
I hear it's pretty common when using polymorphism.


But you weren't "using polymorphism".
The object's actual type was known in the scope where you deleted it.
You might as well write:

void* p = (void*)(new Derived);

if you are going to conceal the objects actual type.


My compiler objects to the next line,

p->DoStuff();

Does this "void" type of which you speak have any virtual functions I
could usefully call?
(I'm not kidding.
Some C programmers actually write "object oriented" code this way.)


This is comp.lang.C++
--
Richard Herring
Oct 7 '05 #20
> But it isn't good programming practice in C++.
Your program already knows about types Derived1 and Derived2
so you might as well use them in the calling program.


You're confused. That is a very common pattern in C++ programs and well
accepted, nothing bad or magical is happening.

The whole point is that the program doesn't already "know" about the
types Derived1 and Derived2 in the scope where it only sees Base*, it
only knows the common interface to the base class. If the destructor
isn't virtual, how the correct destructor is called, you propose to
work around this.. how?

Oct 12 '05 #21
> You might as well write:
void* p = (void*)(new Derived);
if you are going to conceal the objects actual type.
No, you may not if you prefer to call the (correct) destructor. This
whole thread is about virtual destructors.. you're missing the point by
a country mile.
(I'm not kidding.
I'm not laughing.
Some C programmers actually write "object oriented" code this way.)


Those same people usually store pointer-to-destructor-function in the
"base" struct, too, so that proper cleanup routine can be called.
That's what the "virtual" keyword does in C++ in practise, keeps a
pointer to destructor in memory that is accessible through the
pointer-to-object (very commonly this is called pointer-to-VTBL, each
virtual class has unique VTBL which has pointer to every method of the
class).

We are not talking about simple memory allocation but also code that is
actually being called. The difference is not-so-subtle so it is not
clear why you don't see it as clearly as the rest of us apparently seem
to do.

Oct 12 '05 #22
persenaama wrote:
We are not talking about simple memory allocation but also code that is
actually being called. The difference is not-so-subtle
so it is not clear why you don't see it as clearly
as the rest of us apparently seem to do.


You have *not* shown us an example
where a virtual destructor is required.

If C++ required a virtual destructor
for every class that had virtual functions,
the compiler would make the destructor virtual automatically.
A virtual destructor call can be very costly if it isn't necessary
so it isn't required.

Marcus Kwok's example shows how a virtual destructor
can be used as an excuse to write bad code.
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.

Oct 12 '05 #23
E. Robert Tisdale wrote:
int main(int argc, char* argv[]) {
Derived* d = new Derived;
delete d;
return 0;
}
> g++ -Wall -ansi -pedantic -o main main.cc
> ./main B(void)
D(void)
~D(void)
~B(void)

But, of course, allocation from free store was unnecessary.
You should have substituted:

int main(int argc, char* argv[]) {
Derived d;
return 0;
}


On a recent project I worked on, a program failed because it allocated
a large C++ object in automatic storage; but worked when it was
dynamically allocated.

Whether stack space or free store is more precious depends on the
system architecture.
If you find yourself in a situation
where you *must* allocate free storage
(you have not shown us such a case yet),


Such a case happens in embedded systems with small stacks.

Oct 12 '05 #24
E. Robert Tisdale <E.**************@jpl.nasa.gov> wrote:
Marcus Kwok's example shows how a virtual destructor
can be used as an excuse to write bad code.
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.


I also posted the portion of the FAQ that explains the situations where
it is necessary to have a virtual destructor. You have not explained
how using a base class pointer to point to a derived class instance is
"bad".

--
Marcus Kwok
Oct 13 '05 #25
> You have *not* shown us an example
where a virtual destructor is required.
Neither have you, infact, the example you posted was missing the point
and you are using it to argue your case. Some idiots might think that
is brilliant.

But if you insist on seeing example where such construct is required,
download Fusion SDK from www.liimatta.org, you are free to browse the
sourcecode. Take a look for example in the include/core/surface.hpp

I am not going to write a complete application here just to amuse my
vanity, because that is what is required to demonstrate the how the
creation pattern and life-time of the object are both involved in the
discussion. Maybe this is just way over your head?
If C++ required a virtual destructor
for every class that had virtual functions,
the compiler would make the destructor virtual automatically.
You could also write: "If C++ required virtual functions for every
class, the compiler would make the functions virtual automatically.",
and make such as much sense. Would that be a good argument against
virtual methods? No, it wouldn't. Neither is your argument above a good
one against virtual destructors. Let's face it: it is just a method
which is called implicitly when the object is being deleted.

I counter your statement with a question of mine. "If the C++ didn't
require virtual destructor, why the designer of the language and the
standardization comittee included the feature in the language?"

The question is hypothetical, you know the answer already don't you?
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.


Yes, I can see that you are misguided and confused. If there isn't code
you want to call when a polymorphic object is destroyed, you don't need
a virtual destructor. Where you go wrong is that you are yelling
"incompetent" to anyone who does, because it makes you look incompetent
yourself.

Yes, every feature has a price attached. It is a good rule-of-thumb to
follow, however, that when you have a polymorphic class it is a good,
safe and sound practise to make the base class to have a virtual
destructor. The price to pay for code that doesn't suddenly explode on
your face is a small one.

If you aren't a believer of "destructors", don't use'em.

Oct 13 '05 #26
Oh what the hell, here's a complete application where you might want to
see "virtual destructor" being used, the whole usage pattern and
everything:

// begin app source
#include <fusion/core/surface.hpp>
using namespace fusion;

int main()
{
core::init();

// create surface object from a filestream
// (compressed file in this case)
core::surface* picture = core::surface::create("test.zip/test.dds");

// at this point, picture object can be bitmap, cubemap, mipmap..
// since the interface is abstract one, in other words, pure virtual,
// no implementation detail is visible in the surface class..
therefore,
// we must be able to cleanup, free any resources the constructor did
// allocate.. to do this.. we must have a mechanism to call the right
cleanup
// code.. this mechanism is "the virtual destructor", it is typically
invoked like this:
//
// delete picture;
//
// however, in this case we have "resource managed" objects, so we
write
// instead:

picture->release();

// .. but what detail is not relevant to this discussion, because
that is just a simple
// reference counting system, internally it WILL do a call to delete
this; to the
// surface object
}

// end app source

There you go, Tisdale. A complete example of usage pattern where
virtual destructor is useful construct. Knock yourself out.

The header file, I uploaded it here so that you can look at it w/o
downloading the whole kit:

http://www.liimatta.org/misc/surface.hpp

This is called, by-the-way, the "factory design pattern", you might
have heard of it.. maybe just convenient amnesia so that you can play
the "I'm dumb please explain it to me" -game.

Oct 13 '05 #27

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

11 posts views Thread by Stub | last post: by
39 posts views Thread by Ele | last post: by
11 posts views Thread by santosh | last post: by
37 posts views Thread by WittyGuy | last post: by
4 posts views Thread by Tony Johansson | last post: by
7 posts views Thread by sam | last post: by
3 posts views Thread by GAURAV AGRAWAL | last post: by
7 posts views Thread by Tonni Tielens | last post: by
reply views Thread by Waqarahmed | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.