Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TObjectList<T>.Clear not free objects?

I just noticed that

var
  ObjList : TObjectList <TMyObject>;
...
ObjList := TObjectList <TMyObject>.Create (True);
ObjList.Add (TMyObject.Create);
ObjList.Clear;

does not free the object. Looking at the source code it seems that no cnRemoved notification is triggered in Clear (inherited from TList <T>).

My question: Is this intentional? Is there any reason why one does not want to get these notifications in the case of Clear? Or can this be considered as a bug in the collection classes?

EDIT

Turns out that a I put the line

inherited Create;

on the top of TMyObject destructor, which was supposed to go into the constructor. This is why I got memory leaks reported that looked like the TObjectList was not freeing the items. And a look at the source convinced me (I was trapped by the Count property). Thanks for your help anyway!

like image 247
jpfollenius Avatar asked Jun 29 '11 08:06

jpfollenius


2 Answers

The list frees owned objects when you call .Clear. You've got a testing error. The code sample below, written on Delphi XE, displays this:

Calling CLEAR
Object deleted.
Object deleted.
After CLEAR. Press ENTER to free L and Exit.

The code in TList<T>.Clear is deceiving, because Count is actually a property. Look at SetCount(), then look at DeleteRange() and you'll see the code for Notify(oldItems[i], cnRemoved) at the end of the DeleteRange procedure.


program Project3;

{$APPTYPE CONSOLE}

uses SysUtils, Generics.Collections;

type
  TDelObject = class
  public
    destructor Destroy;override;
  end;

{ TDelObject }

destructor TDelObject.Destroy;
begin
  WriteLn('Object deleted.');
  inherited;
end;

var L:TObjectList<TDelObject>;

begin
  L := TObjectList<TDelObject>.Create(True);
  L.Add(TDelObject.Create);
  L.Add(TDelObject.Create);
  WriteLn('Calling CLEAR');
  L.Clear;
  WriteLn('After CLEAR. Press ENTER to free L and Exit.');
  Readln;
  L.Free;
end.
like image 161
Cosmin Prund Avatar answered Sep 26 '22 12:09

Cosmin Prund


TList<T>.Clear calls DeleteRange to do the work. The last part of DeleteRange runs around all the items calling Notify passing cnRemoved.

Your analysis of the code is thus incorrect. The cnRemoved notification is duly delivered and owned objects are freed.

like image 32
David Heffernan Avatar answered Sep 25 '22 12:09

David Heffernan