Clear a TList or a TObjectList
Asked Answered
D

6

17

I'm a bit puzzled of what to use for storing objects in a list. Until now I have used TList and freed each item in a loop. Then I discovered TObjectList that do this automatically from Free. Then I saw this from the doc of TList.Clear:

Call Clear to empty the Items array and set the Count to 0. Clear also frees the memory used to store the Items array and sets the Capacity to 0.

So it is basically the same. So

for TList

mylist.Clear;
myList.Free;

is the same as for TObjectList?

myList.Free;

Can TObjectList only be used for items as classes or can I store records?

Derisive answered 2/5, 2012 at 8:15 Comment(1)
The part you quote is only "basically the same" if you don't read the TObjectList documentation carefully: "If the OwnsObjects property is set to true (the default), TObjectList controls the memory of its objects, freeing an object when its index is reassigned; when it is removed from the list with the Delete, Remove, or Clear method; or when the TObjectList instance is itself destroyed." TList's documentation says nothing about that behavior. That's the fundamental difference between the two classes.Wait
T
24

1. TList won't free the elements, with both Clear or Free.

aList.Clear;

Will just set aList.Count := 0 without freeing the aList.Items[] elements. So you'll leak memory. You'll need an explicit free as such:

for i := 0 to aList.Count-1 do
  TObject(aList[i]).Free;

But this is what TObjectList does... :)

About TObjectList, it is worth saying that TObjectList.Destroy is calling Clear.

So

aObjectList.Clear;
aObjectList.Free;

is exactly the same as

aObjectList.Free;

2. To store a list of records, you can use a dynamic array.

You'll get all TList methods (and more) with our dynamic array wrapper. That is, Add / Delete / Clear / Count / IndexOf / Find...

It has built-in serialization features (in binary or JSON), automated sorting and comparison (using RTTI) which are not existing with a TList/TObjectList. From Delphi 5 and later.

With more modern version of Delphi, you may use generics to handle the dynamic array, if you do not want to use a third-party library.

Tremolite answered 2/5, 2012 at 8:41 Comment(2)
Just a clearification about TObjectList. It has a property: OwnsObjects (default = true) which controls if the objects in the list are being freed when items are removed.Controvert
@LURD You are right. This property may be handy, but also misleading: you may suppose that objects will be freed, but if you set OwnObjects := false somewhere in the code (even at runtime), you would easily leak memory or resources: so to be used with care! I prefer a clear TList / TObjectList separation.Tremolite
M
13

It's not the same TList.Clear only frees the memory allocated to store the pointers, not objects they are pointing to. To avoid memory leaks you need to free the memory yourself - as you have been doing - or use TObjectList.

To answer the second question, TObjectList doesn't support storing records. You need to use TList (or something else) in that case.

Moorhead answered 2/5, 2012 at 8:18 Comment(1)
Know managing records in a TList requires quite some effort though.Syphon
P
10

Read what the documentation is saying more carefully:

Clear also frees the memory used to store the Items array

Only the memory for the array itself is freed, not the memory used by individual elements inside the array.

Philipphilipa answered 2/5, 2012 at 18:56 Comment(0)
J
9

If you are using a recent version of Delphi I suggest that you use a generic list.

Right now you probably need to do a lot of casting when you use the objects from the list. With a generic list you don't have to do that anymore.

For instance if you have:

TMyObject = class(TObject);

Then you make the list like this:

TMyObjectList = TObjectList<TMyObject>;

There is an article in the Embarcadero Wiki:

http://docwiki.embarcadero.com/CodeExamples/XE8/en/Generics_Collections_TObjectList_(Delphi)

Jugal answered 2/5, 2012 at 8:54 Comment(0)
S
0

Really watching the TObjectList code in contnrs.pas OwnObjects does nothing. FOwnObjects is a variable declared in the private part of TObjectList that is not used anywhere in the TObjectList code (except just assigning the value), and there is no overridden Clear procedure in it.

So I'm afraid it necessary to free the memory just the same as in TList.

Stiffen answered 21/11, 2013 at 11:14 Comment(1)
The property TObjectList.OwnsObjects is true by default. You can change the property value after creation. If this property is true when calling TObjectList.Free, all objects in the list will be deallocated automatically.Controvert
D
0

@Sebastian Zartner: look at "TObjectList.Notify" - there you can see, that it calls "Free" for the items in case "OwnsObjects" is set:

procedure TObjectList.Notify(Ptr: Pointer; Action: TListNotification);
begin
  if OwnsObjects then
    if Action = lnDeleted then
      TObject(Ptr).Free;
  inherited Notify(Ptr, Action);
end
Deadlock answered 4/3 at 10:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.