[DUG] How's this for inconsistent

Todd todd.martin.nz at gmail.com
Wed Nov 24 20:08:28 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;
>
Upon reflection, that would only work for a TComponent descendant.
>
> 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.
>
> *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/17d6f9e3/attachment-0001.html 


More information about the Delphi mailing list