Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi reference counting for subclasses

Tags:

delphi

Say that I have a situation like this:

ITest = interface
 procedure somethingHere();
end;

TImpl = class(TInterfacedObject, ITest)
 procedure somethingHere();
end;

TImplSub = class(TImpl)

end;

Given the code above I am able to use this kind of code without any memory leak if I don't use the try-finally statement:

var a: ITest;
begin
 a := TImpl.Create;
end;

Is this the same for the subclass?

var a: ITest;
begin
 a := TImplSub.Create;
end;

I think that since TImplSub is a subclass of TImpl, TImplSub inherits TInterfacedObject and ITest from the father. Does the above code leak?

This may be not related but how can I check if the code above leaks or not?

like image 669
Rosanna Trevisan Avatar asked Jan 15 '18 21:01

Rosanna Trevisan


People also ask

Why doesn't Delphi support automatic reference counting of variables?

The reason for that is that Delphi's automatic reference counting only works with interfaces. With variables declared as interfaces, automatic reference counting will be handled by the compiler, and you will not have to put in any deallocation calls in order to prevent memory leaks.

What happens when the reference count goes to zero?

When the reference count goes to zero, the object is disposed of. Failure to do the reference counting correctly results in bugs that are sometimes very hard to diagnose. Symptoms of such bugs may be objects "disappearing" for unknown reason, or memory leaks.

Does quickopc count com references in Delphi?

QuickOPC is not special in respect to COM reference counting, and the rules that apply to QuickOPC usage in Delphi are the general rules that apply to any COM component. We have, however, put together a short set of recommendations that should help you to write bug-free code more easily, in this respect.


2 Answers

Reference counting for interface references is triggered with _AddRef and _Release methods that are in this case implemented in TInterfacedObject. Your subclass inherits that reference counting behavior.

You can use, actually you must use, interface references to store your subclassed object instance, the way you coded it. (Not using interface reference for storing reference counted object instances breaks reference counting mechanism)

Following code does not leak, and does not require try...finally block because destruction is automatic.

var a: ITest;
begin
 a := TImplSub.Create;
end;

To check for memory leaks under Windows compiler you can use ReportMemoryLeaksOnShutdown

begin
  ReportMemoryLeaksOnShutdown := true;
  ...
end.

Another way of testing whether object is destroyed while you are investigating specific behavior is to override destructor and set breakpoint there.

like image 69
Dalija Prasnikar Avatar answered Nov 15 '22 21:11

Dalija Prasnikar


Thanks to the comments (@nil user) I have managed to make a test like this

type
 ITest = interface
   procedure test;
 end;

 TProva = class(TInterfacedObject, ITest)
   procedure test;
 end;

 TProvaSub = class(TProva)
   procedure testDue;
 end;

And then if you try to run this code (in debug mode with F9):

procedure TForm1.Button1Click(Sender: TObject);
var a: ITest;
begin    
 a := TProvaSub.Create;
 a.test;    
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  ReportMemoryLeaksOnShutdown:=DebugHook<>0;
end;

WHen I close the form I DON'T have a leak report.


My conclusion: TProvaSub has a piece of TProva inside itself (since it's a subclass) and so it inherits the _AddRef and _Release. So the code is good and doesn't leak!

like image 40
Rosanna Trevisan Avatar answered Nov 15 '22 19:11

Rosanna Trevisan