Hi Jolyon
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.
I fixed it like this
procedure TamObject.BeforeDestruction;
begin
//add a reference count, in case an interface is acquired and
released during destruction
InterlockedIncrement(FCount);
inherited BeforeDestruction;
end;
procedure TamObject.FreeInstance;
begin
//remove the reference count added in BeforeDestruction
InterlockedDecrement(FCount);
assert(FCount = 0,'Destroying object with non-zero reference count');
inherited FreeInstance;
end;
Of course, an interface can still not be referenced in descendant
BeforeDestruction methods, (since the inherited method is usually called
at the end), but can be safely referenced in the destructor.
Todd.
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