[DUG] How's this for inconsistent
Todd
todd.martin.nz at gmail.com
Wed Nov 24 19:51:50 NZDT 2010
> Yep -- I remember that my fix was to set the "destructing" state
> indicator in a BeforeDestruction() override. This was then tested in
> _Release() to render it a NO-OP during execution of the destructor
> chain (incomplete, obviously, just to give the idea):
>
> Procedure BeforeDestruction;
>
> SetState(csDestroying);
>
> Function _Release;
>
> If csDestroying in State then EXIT;
>
> Nothing else needs be done, as long as any further BeforeDestruction
> overrides call inherited before doing their work, which they should do
> (in my framework I introduced another virtual to be overridden in my
> descendants, in case there were occasions when work was done to
> generate references during the destructor execution -- even in your
> case, the FreeInstance() override is redundant I think, other than as
> a sanity/safety check and so could be made subject to some conditional
> compilation flag.
>
True. I used an "assert", since it can be eliminated by the compiler,
but the decrement still remains.
There's always more than one way to skin the cat. I like the do/undo
pattern.
The whole problem could be eliminated entirely if TInterfacedObject just
broadcast a message when its reference count hit zero, rather than
destroying itself. Then some other object (garbage collector) listening
for that message, could decide what to do with the it. I'm wondering
about whether TObject.Dispatch could achieve this.
>
> *From:* delphi-bounces at delphi.org.nz
> [mailto:delphi-bounces at delphi.org.nz] *On Behalf Of *Todd
> *Sent:* Wednesday, 24 November 2010 6:15 p.m.
> *To:* NZ Borland Developers Group - Delphi List
> *Subject:* Re: [DUG] How's this for inconsistent
>
> Actually, this would be better
>
> function TamObject._Release: Integer;
> begin
> Result := InterlockedDecrement(FCount);
> if (FCount = 0) then
> begin
> //add a reference count, incase an interface is acquired and
> released during destruction
> InterlockedIncrement(FCount);
> self.Destroy;
> end;
> end;
>
> procedure TamObject.FreeInstance;
> begin
> //remove the reference count added in _Release
> InterlockedDecrement(FCount);
> assert(FCount = 0,'Destroying object with non-zero reference count');
> inherited FreeInstance;
> end;
>
> I spotted that they fixed that a while ago -- I remember having to fix
> the issue myself many years ago so was quite pleased to see that it
> was now taken care of in TInterfaceObject as a matter of course. For
> some reason I never noticed the omission of the same facility in the
> destructor. And yes, it's a [potentially] big problem.
>
> I need to think about this tho... setting a fake ref count during
> execution of the constructor is safe enough as you know precisely when
> construction is done and to restore the ref count back to zero.
>
> Setting a fake ref count during destruction strikes me as more
> problematic and makes me nervous, but I can't quite put my finger on
> why. It might be nothing. That doesn't mean it can't be fixed, only
> that the solution put in place for construction might not work for
> destruction and it wasn't felt necessary to do any extra work for a
> more comprehensive solution.
>
> Certainly in the case of my code where I fixed this I had specific
> "constructing" / "destructing" state markers (it wasn't a general
> purpose interfacedobject class but a base class in a far richer
> framework that happened to also implement its own version of IUnknown)
> -- I know I didn't rely on side effects of a faked ref count.
>
> *From:* delphi-bounces at delphi.org.nz
> <mailto:delphi-bounces at delphi.org.nz>
> [mailto:delphi-bounces at delphi.org.nz] *On Behalf Of *Todd
> *Sent:* Wednesday, 24 November 2010 16:55
> *To:* NZ Borland Developers Group - Delphi List
> *Subject:* [DUG] How's this for inconsistent
>
> The Delphi developer who implemented TInterfacedObject obviously
> considered the case when an interface reference is grabbed during
> construction......
>
> // Set an implicit refcount so that refcounting
> // during construction won't destroy the object.
> class function TInterfacedObject.NewInstance: TObject;
> begin
> Result := inherited NewInstance;
> TInterfacedObject(Result).FRefCount := 1;
> end;
>
> procedure TInterfacedObject.AfterConstruction;
> begin
> // Release the constructor's implicit refcount
> InterlockedDecrement(FRefCount);
> end;
>
> but didn't consider applying the same logic during destruction. So
> grabing an interface reference during destruction causes all hell to
> break loose, as the _Release method tries to free the object again and
> again recursively.
>
> procedure TInterfacedObject.BeforeDestruction;
> begin
> if RefCount <> 0 then
> Error(reInvalidPtr);
> end;
>
> function TInterfacedObject._Release: Integer;
> begin
> Result := InterlockedDecrement(FRefCount);
> if Result = 0 then
> Destroy;
> end;
>
> Todd.
>
>
>
> _______________________________________________
> NZ Borland Developers Group - Delphi mailing list
> Post:delphi at delphi.org.nz <mailto:delphi at delphi.org.nz>
> Admin:http://delphi.org.nz/mailman/listinfo/delphi
> Unsubscribe: send an email todelphi-request at delphi.org.nz <mailto:delphi-request at delphi.org.nz> with Subject: unsubscribe
>
>
> _______________________________________________
> NZ Borland Developers Group - Delphi mailing list
> Post: delphi at delphi.org.nz
> Admin: http://delphi.org.nz/mailman/listinfo/delphi
> Unsubscribe: send an email to delphi-request at delphi.org.nz with Subject: unsubscribe
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://listserver.123.net.nz/pipermail/delphi/attachments/20101124/63987ab6/attachment.html
More information about the Delphi
mailing list