Re: [RFC] cbdataFree does not call destructor

From: Henrik Nordström <henrik_at_henriknordstrom.net>
Date: Sat, 07 Jul 2012 21:38:08 +0200

lör 2012-07-07 klockan 09:25 -0600 skrev Alex Rousskov:

> > The cbdata interface do not fit entirely to new/delete. The difference
> > is that cbdataFree only marks objects as "to be freed". There may still
> > be reference counts keeping it alive.
>
> That is what "delete foo" does as well if foo's type has CBDATA_CLASS2
> macros or equivalent. Remember that
>
> delete foo
>
> in this context essentially means this:
>
> if (foo) {
> foo->~Foo(); // call the destructor (#1)
> Foo::delete(foo); // call the delete method (#2)
> }

Yes, the destructor is called on delete while there still is cbdata
references active, and later deallocated when the last cbdata reference
is gone. This means that it is NOT ok to access the object via a cbdata
reference.

> The destructor call itself (#1) never deallocates object memory. The
> delete method call (#2) usually deallocates object memory but does not
> really have to, and that is what CBDATA_CLASS2 macros (and friends)
> abuse to emulate cbdataFree().

yes, and is not how cbdata was meant to tear down objects.

a better match would have been a cbdata free callback invoking the
destructor.

but in most cases it's not an issue. much of this stems from the
ambiguous meaning of a cbdata reference which was a design mistake.
cbdata references are both meant to be reference counts only not valid
to access the object as such (only in callback to the owner) an type
preserving. Should have been pure references only only valid to use in
callback hanler.

> > But this said cbdata really SHOULD get replaced by type hiding refcount
> > + invalidation. Moving to CBDATA_CLASS macros is a good step towards
> > that.
>
> Agreed (though I am not sure what you mean by "type hiding" here).

That the type is only known to the owner, not the one doing a callback.

Today cbdataReference preserves the type of the referenced object, where
it really should hide the type so that the one keeping a reference not
by mistake thinks that it's ok to access the object via the cbdata
reference.

> "destructed" in your context means calling the destructor. For PODs,
> calling the destructor is a no-op, essentially.

cbdata have it's own destructor, called when the object is truly freed.

But this is not used by CBDATA_CLASS2, causing an interface mismatch.
CBDATA_CLASS2 always registers NULL as the destructor.

> The interface provided by cbdata*(), you mean? Yes, I agree. And that
> creates problems with properly cleaning up non-PODs because to proper
> clean a non-POD you must know its exact type.

In the cbdata interface ad originally designed every complex data type
(struct or class, no difference) needing a destructor should have a
suitable cbdataFreeCB callback for tearing down the object, and never
use delete as a substitute for cbdataFree(). There is no difference
between C & C++ there.

But as said this is really a design error in cbdata. The only reason why
this is needed instead of doing the descruction immediately on
cbdataFree is because cbdataReference refrences are non-anonymous and
may continue to access the object.

Regards
Henrik
Received on Sat Jul 07 2012 - 19:38:14 MDT

This archive was generated by hypermail 2.2.0 : Sun Jul 08 2012 - 12:00:03 MDT