[fpc-pascal] A serious Memleak using delegates/implements (was: Delegate Interface class does not seem to be referenced counted)
Tony Whyman
tony.whyman at mccallumwhyman.com
Fri Oct 7 16:02:05 CEST 2016
On 07/10/16 12:29, stdreamer wrote:
> The point is that you are trying to equate delegation with contained
> objects/interfaces and that is not what delegates are about.
> Delegation has nothing to do with the underlined mechanism you choose
> to use.
Hmm, not so sure about that. I have updated my original example from
August to use TContainedObject (see below). As a workaround for the
interface delegation problem it works, as long as you don't try and use
TDelegateClass on its own. This is because although it appears as a
reference counted com interface, it still relies upon another object to
free it. The example returns:
Creating TDelegateClass
Creating TMyClass
Creating TDelegateClass
Destroying TMyClass
Destroying TDelegateClass
i.e. there is a missing call to the TDelegateClass destructor. This is
because I created it standalone (in "DoRun) just to illustrate the point.
There is a real need to update the FPC manual to include
TContainedObject. It's importance for interface delegation and its
limitations. How you implement interface delegation clearly has a big
outcome on how the interface is used by the user.
program project1;
{$mode objfpc}{$H+}
uses
{$IFDEF UNIX}{$IFDEF UseCThreads}
cthreads,
{$ENDIF}{$ENDIF}
Classes, SysUtils, CustApp
{ you can add units after this };
type
{ TDelegateTest }
TDelegateTest = class(TCustomApplication)
protected
procedure DoRun; override;
public
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
procedure WriteHelp; virtual;
end;
IMyInterface = interface
procedure P1;
end;
{ TDelegateClass }
TDelegateClass = class(TContainedObject, IMyInterface)
private
procedure P1;
public
constructor Create(aController: IUnknown);
destructor Destroy; override;
end;
{ TMyClass }
TMyClass = class(TInterfacedObject, IMyInterface)
private
FMyInterface: TDelegateClass;
property MyInterface: TDelegateClass
read FMyInterface implements IMyInterface;
public
constructor Create;
destructor Destroy; override;
end;
{ TDelegateClass }
procedure TDelegateClass.P1;
begin
writeln('P1');
end;
constructor TDelegateClass.Create(aController: IUnknown);
begin
inherited Create(aController);
writeln('Creating ',ClassName);
end;
destructor TDelegateClass.Destroy;
begin
writeln('Destroying ',ClassName);
inherited Destroy;
end;
{ TMyClass }
constructor TMyClass.Create;
begin
inherited Create;
FMyInterface := TDelegateClass.Create(self);
writeln('Creating ',ClassName);
end;
destructor TMyClass.Destroy;
begin
writeln('Destroying ',ClassName);
if FMyInterface <> nil then FMyInterface.Free;
inherited Destroy;
end;
{ TDelegateTest }
procedure TDelegateTest.DoRun;
var Intf: IUnknown;
Intf2: IMyInterface;
begin
Intf := TMyClass.Create;
Intf2 := TDelegateClass.Create(Intf); {never destroyed}
// stop program loop
Terminate;
end;
constructor TDelegateTest.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
StopOnException := True;
end;
destructor TDelegateTest.Destroy;
begin
inherited Destroy;
end;
procedure TDelegateTest.WriteHelp;
begin
{ add your help code here }
writeln('Usage: ', ExeName, ' -h');
end;
var
Application: TDelegateTest;
begin
Application := TDelegateTest.Create(nil);
Application.Title := 'Interface Delegation Test';
Application.Run;
Application.Free;
end.
More information about the fpc-pascal
mailing list