No, the "State" and "csDestroying" elements were part of my framework, not
the mechanism that is part of TComponent (though of course there were
obvious parallels in some cases - note however that TComponent uses
ComponentState, not just "State" and ControlState is introduced by the
controls part of the VCL hierarchy also). 

 

My changes in the case that I am dragging up from the dim and distant past
were not to create a replacement general purpose TInterfacedObject as such,
but part of a much wider framework that happened to have at its core a class
that implemented IUnknown along with a whole host of other services as part
of that framework since the entire thing was interface based.

 

 

On a more general point, I'd say that whilst referencing "self" as an
interface is an almost unavoidable part of any interface based framework,
the same is not true in the destructor.  Anything referenced or notified
during destruction of an object that requires being passed a reference TO
that object, could and most likely should, have been passed a reference to
that object during construction or during some later operation.

 

 

However, if those other objects were holding on to those references, that
would prevent the object from being destroyed in the first place.

 

Another thing that is missing is a safe, common implementation of a weak
reference (an interface reference that does not hold on to - i.e. does not
contribute +1 toward - the reference count of the referenced object). You
can use an interface reference cast as a Pointer, but the catch is that the
reference must be sure that it will be notified if the referenced object is
destroyed, so that it can NIL itself.  Using a plain Pointer won't do... you
have to wrap it inside some object that can register for those notifications
(and be sure that the object referenced will implement the required
notification for the wrapper to respond to).

 

Coincidentally, just this weak [sic] I found myself implementing exactly
that, leveraging my TMultiCastNotify work and IOn_Destroy multicast destroy
notification framework to take care of all that.

 

But, that is not a general purpose solution as it requires that objects
exposing interfaces that may be encapsulated in my weak reference
implementation also implement IOn_Destroy, which is not built into the VCL.
In fact, the VCL doesn't have any such general purpose system (and neither
should it have imho).  The FreeNotification() mechanism is not supported on
TObject, and neither imho should it be.

 

Not every application - or indeed every object - needs these things, nor the
overhead that it would incur, adding housekeeping code to the tear-down of
every object.

 

Most applications simply don't need these sorts of exotica (as evidenced by
the fact that these sort of facilities either don't exist at all or took so
long to be introduced into the core VCL, following the introduction of
interfaces waaaaaay back in Delphi 3 - Delphi 2 did things slightly
differently you may recall).

 

 

The very beauty of Delphi and the VCL is that we can introduce these things
into the applications (or indeed the small parts of our applications) that
need them, without imposing them on everything else.

 

When we want the convenience of having everything to hand whether you want
it or not, that's what managed code is for.  J

 

 

 

From: delphi-boun...@delphi.org.nz [mailto:delphi-boun...@delphi.org.nz] On
Behalf Of Todd
Sent: Wednesday, 24 November 2010 8:08 p.m.
To: NZ Borland Developers Group - Delphi List
Subject: Re: [DUG] How's this for inconsistent

 





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-boun...@delphi.org.nz [mailto:delphi-boun...@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-boun...@delphi.org.nz [mailto:delphi-boun...@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@delphi.org.nz
Admin: http://delphi.org.nz/mailman/listinfo/delphi
Unsubscribe: send an email to delphi-requ...@delphi.org.nz with Subject:
unsubscribe

 

 
 
_______________________________________________
NZ Borland Developers Group - Delphi mailing list
Post: delphi@delphi.org.nz
Admin: http://delphi.org.nz/mailman/listinfo/delphi
Unsubscribe: send an email to delphi-requ...@delphi.org.nz with Subject:
unsubscribe

 

_______________________________________________
NZ Borland Developers Group - Delphi mailing list
Post: delphi@delphi.org.nz
Admin: http://delphi.org.nz/mailman/listinfo/delphi
Unsubscribe: send an email to delphi-requ...@delphi.org.nz with Subject: 
unsubscribe

Reply via email to