Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

About virtual destructor for polymorhism deletion

29 views
Skip to first unread message

JiiPee

unread,
Aug 20, 2015, 5:08:45 PM8/20/15
to
I think its Sutter who writes:
http://www.gotw.ca/publications/mill18.htm
// Example 3: Obvious need for virtual destructor.
class Base { };

class Derived : public Base {};

Base* b = new Derived;
delete b; // Base::~Base() had better be virtual!

So he wants:
class Base {
public:
virtual ~Base() {}
};

class Derived : public Base {};

Base* b = new Derived;
delete b;

And this works. But...it seem to me that I can get it even working
without a virtual destructor ! Like this:
class Base {
public:
~Base() {}
};

class Derived : public Base {};

Base* b = new Derived;
delete (Derived*)b;

Its not virtual but seems to work the same as the virtual version.
So, just wondering why he said "it better be virtual" as I can show here
that there is a way to get it working without virtuality. Or is there a
mistake in my version? I tested it... it seems to delete all objects
from all classes.

Yeah, I understand delete (Derived*)b; is not a good way to do stuff....
but is that the only issue here?

Ian Collins

unread,
Aug 20, 2015, 5:12:07 PM8/20/15
to
Do you need another?

--
Ian Collins

JiiPee

unread,
Aug 20, 2015, 5:15:24 PM8/20/15
to
On 20/08/2015 22:11, Ian Collins wrote:
> JiiPee wrote:
>>
>>
>> Yeah, I understand delete (Derived*)b; is not a good way to do stuff....
>> but is that the only issue here?
>
> Do you need another?

ok i see... we can do that trick (and its deleting everything ok), but
its very bad way to program thats why he did not even mention it. ok,
but am just trying to undertand....

Bo Persson

unread,
Aug 20, 2015, 5:26:40 PM8/20/15
to
Yes, but generally when you need to work through an interface base
class, you have more than one derived type. Then you don't know which
one you should cast the pointer to.


Bo Persson

Paavo Helde

unread,
Aug 20, 2015, 5:37:59 PM8/20/15
to
JiiPee <n...@notvalid.com> wrote in news:glrBx.332484$0B6.1...@fx27.am4:
>
> And this works. But...it seem to me that I can get it even working
> without a virtual destructor ! Like this:
> class Base {
> public:
> ~Base() {}
> };
>
> class Derived : public Base {};
>
> Base* b = new Derived;
> delete (Derived*)b;
>

The problem is that in real life you will not have a single Derived
class, but maybe tens of different classes derived directly or indirectly
from Base. Note that the deletion code typically has no idea which exact
class it is dealing with (otherwise it could access it via the correct
pointer, not Base*). Now you will have to somehow find out which exact
class you have, maybe by repeated dynamic_casts, and huge if-else blocks
for executing the correct delete.

The real fun starts if dynamic load libraries are involved and some
derived classes might not be accessible or even not yet written when you
ship the library containing the Base deletion code. You cannot write a
dynamic_cast to a class which does not exist yet!

HTH
Paavo

Alf P. Steinbach

unread,
Aug 20, 2015, 6:59:04 PM8/20/15
to
On 20.08.2015 23:08, JiiPee wrote:
> I think its Sutter who writes:
> http://www.gotw.ca/publications/mill18.htm
> // Example 3: Obvious need for virtual destructor.
> class Base { };
>
> class Derived : public Base {};
>
> Base* b = new Derived;
> delete b; // Base::~Base() had better be virtual!
>
[snip]
>
> class Derived : public Base {};
>
> Base* b = new Derived;
> delete (Derived*)b;
>
> Its not virtual but seems to work the same as the virtual version.
> So, just wondering why he said "it better be virtual" as I can show here
> that there is a way to get it working without virtuality.

In most code the deleting action is automated.

The cast you use is automated by std::shared_ptr (provided the complete
type is known at the point of construction), but e.g. std::unique_ptr
does not remember the original when the smart pointer is upcasted.


> Or is there a
> mistake in my version? I tested it... it seems to delete all objects
> from all classes.

It's technically OK, just as using goto is technically OK.

It's just very fragile, very error-prone.


> Yeah, I understand delete (Derived*)b; is not a good way to do stuff....
> but is that the only issue here?

No.

For example, the destructor might be the only method available to make
Base polymorphic (at least one virtual function), which it needs to be
for typeid and dynamic_cast (called RTTI, Run-Time Type Information).


Cheers & hth.,

- Alf

Paavo Helde

unread,
Aug 21, 2015, 1:50:47 PM8/21/15
to
Udo Steinbach <tras...@udoline.de> wrote in
news:mr773f$eu2$1...@dont-email.me:

>> Now you will have to somehow find out which exact class you have,
>> maybe by repeated dynamic_casts, and huge if-else blocks for
>> executing the correct delete.
>
> or carry an extra pointer,
> http://www.thradams.com/codeblog/type_ptr3.htm

Looked at this page. Looks to me mostly like Boost.Any except for the
select<> template which performs all these repeated if checks and type
comparisons under the carpet, to figure out the actual type. But yes, in
overall it seems like a nifty way to add polymorphism to types which don't
have any.

And yes, this solution indeed contains an example of appropriate usage of:

delete (T*) p;

(a better style would be of course to use static_cast<T*>(p)).

Cheers
Paavo
0 new messages