LWN.net Logo

Apache resigns from the Java Community Process executive committee

Apache resigns from the Java Community Process executive committee

Posted Dec 14, 2010 22:14 UTC (Tue) by foom (subscriber, #14868)
In reply to: Apache resigns from the Java Community Process executive committee by cmccabe
Parent article: Apache resigns from the Java Community Process executive committee

While of course you're exactly right that calling the destructor on Foo when the instance is of Bar is a bad mistake to make, your *particular* example, at least with gcc, will not cause a memory leak. That is simply because Bar's destructor doesn't do anything. The only action taken, in the end, is to call free(my_foo), which works perfectly well and still releases all the memory when my_foo is a "Bar" object rather than the Foo object it is declared to be.

Now, if, instead of "int b;", you'd put "std::string b;" as the member of Bar, then you'd have an actual leak. :)


(Log in to post comments)

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 0:51 UTC (Wed) by paulj (subscriber, #341) [Link]

Serious? The destructor that gets called is the base class, not that of instantiated type of the object, cause the shared_ptr uses the base class type? Is that a flaw in shared_ptr or in the underlying language? That's just amazing...

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 2:03 UTC (Wed) by nix (subscriber, #2304) [Link]

That's because the destructor isn't virtual. That's what the absence of virtual *means*. (Now perhaps the fact that virtual wasn't default, with lack-of-virtual an option, *is* a language flaw.)

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 7:08 UTC (Wed) by paulj (subscriber, #341) [Link]

Ah yes, of course. Keep forgetting about C++'s selective inheritance.

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 2:14 UTC (Wed) by foom (subscriber, #14868) [Link]

No no, you misunderstand. It's not as bad as that. What destructor shared_ptr calls depends on the declared type of the argument in its constructor, not the type of the shared_ptr itself. So, in an idiomatic spelling:
> shared_ptr<Foo> foo(new Bar(5));
everything works fine, because the argument is of type "Bar *" (that being the return type of the new expression).

It's only in the case of:
> Foo *foo_rawptr = new Bar(5);
> shared_ptr<Foo> foo(foo_rawptr);

that you get wrong behavior.

That is a feature of C++ the language: it lets you decide whether you want to keep track of the runtime type of the object or not. "Not" is a very important use-case: it allows you to use many of the features of C++ even in situations where adding a class-pointer word to every instance would be excessively expensive, or impossible (e.g. mmaping a file full of structs from disk).

So anyhow, the *default* is to not track the runtime-type. However, if you mark the destructor "virtual", then it *will* add a word to the size of the object instance to keep track of the actual type, and then delete will call the destructor for "Bar", even in the second case.

Taking shared_ptr out of the picture for simplification, the thing that doesn't work without a virtual destructor is:
> Bar *bar = new Bar(5);
> Foo *foo = bar;
> delete foo;

(that is: where the static type of the argument to delete is different from the dynamic type of the object).

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 3:06 UTC (Wed) by HelloWorld (guest, #56129) [Link]

No no, you misunderstand. It's not as bad as that. What destructor shared_ptr calls depends on the declared type of the argument in its constructor, not the type of the shared_ptr itself.
Whoa! That is certainly a behaviour I didn't expect. Other smart pointer classes like boost::scoped_ptr or std::auto_ptr don't do this, and I really can't think of a reason for making shared_ptr behave that way. Do you know of any rationale for this behaviour?

Apache resigns from the Java Community Process executive committee

Posted Dec 15, 2010 2:24 UTC (Wed) by HelloWorld (guest, #56129) [Link]

> Is that a flaw in shared_ptr or in the underlying language?
shared_ptr has nothing to do with it, the same thing would happen if you'd delete the pointer by hand. The problem stems from the fact Bar's destructor isn't virtual.

I guess the reason for not making destructors virtual by default is that this would be inconsistent with the rest of the language, as other methods aren't virtual by default either. In the very early days of C++, member functions existed but virtual member functions were introduced only later. At that point, Bjarne chose not to make methods virtual by default, but you had to use the virtual keyword to make them. I probably would have done it the other way around, as the worst thing a virtual method call can do is make your program a little slower, while making a non-virtual method call can cause severe bugs.

So, whether this is a flaw in the language depends on whom you ask.

Copyright © 2013, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds