Reputation: 89
I have a TObjectList with few elements. I have to replace one of them with one new at the same item (without change a count). I do the following:
procedure TForm1.Button1Click(Sender: TObject);
var
TObj: TObjectList;
LPoint: TPPoint;
i: integer;
begin
TObj:= TObjectList.Create;
try
for i:= 0 to 3 do
begin
LPoint:= TPPoint.Create(i, i+ 1);
TObj.Add(LPoint);
end;
LPoint:= TPPoint.Create(21, 22);
TObj.Items[1]:= nil;
TObj.Items[1]:= LPoint;
for i:= 0 to 3 do
begin
ShowMessage(IntToStr(TPPoint(TObj.Items[i]).X));
end;
finally
TObj.Free;
end;
end;
My question is: how can I free the replaced element in the memory? The help says "an Objekt will be freed if his Index will be reassigned". Is the command TObj.Items[1]:= nil;
enough?
Thanks in advance for any information.
Upvotes: 2
Views: 977
Reputation: 424
TObjectList.Create() takes care of its items memory management, when created with OwnsObjects = true (default behavior)
I tested it using Delphi XE7 so I cannot guarantee this is exactly the same behavior in Delphi 7. For example, declaring TObj: TObjectList without a type specified is impossible (won't compile).
I used TLabel instead of TPPoint, and renamed the variables so that it is less confusing. To make sure it is freed, I added the ReportMemoryLeaksOnShutdown := True to my dpr. It's definitely a must have to make sure you don't mess with memory. Sadly it appeared in Delphi 2006, so it's not available in Delphi 7.
This code replaces an item in the list without any memory leaks :
procedure TForm3.Button1Click(Sender: TObject);
var
list: TObjectList<TLabel>;
listItem: TLabel;
i: integer;
begin
list:= TObjectList<TLabel>.Create();
try
for i:= 0 to 3 do
begin
listItem:= TLabel.Create(nil);
listItem.Caption := 'list item ' + IntToStr(I);
list.Add(listItem);
end;
listItem:= TLabel.Create(nil);
listItem.Caption := 'list item replaced';
list.Items[1]:= listItem;
for i:= 0 to 3 do
begin
ShowMessage(list.Items[i].Caption);
end;
finally
list.Free;
end;
end;
Upvotes: 1
Reputation: 612784
TObj.Items[1]:= nil;
TObj.Items[1]:= LPoint;
Here you perform two assignments, so the class attempts to free two items.
TObj.Items[1]:= nil;
At this point the previous item is a non-nil reference added in your earlier loop. That object is thus destroyed.
TObj.Items[1]:= LPoint;
When this line executes, TObj.Items[1] = nil
and so the Free
method is called on nil
. Nothing happens.
The bottom line is that your code is overcomplicated. You can replace
TObj.Items[1]:= nil;
TObj.Items[1]:= LPoint;
with
TObj.Items[1]:= LPoint;
The class will destroy the object currently stored in TObj.Items[1]
and then replace it with LPoint
. Just as you want.
Upvotes: 3