I have a question about the behavior of the TObjectList class of Spring4D. In my code, I create a list of geometric shapes, such as square , circle , triange , each of which is defined as a separate class. To automatically remove geometric shapes when the list is destroyed, I defined a list of TObjectList types as follows:
procedure TForm1.FormCreate(Sender: TObject); var geometricFigures: TObjectList<TGeometricFigure>; geometricFigure: TGeometricFigure; begin ReportMemoryLeaksOnShutdown := true; geometricFigures := TObjectList<TGeometricFigure>.Create(); try geometricFigures.Add(TCircle.Create(4,2)); geometricFigures.Add(TCircle.Create(0,4)); geometricFigures.Add(TRectangle.Create(3,10,4)); geometricFigures.Add(TSquare.Create(1,5)); geometricFigures.Add(TTriangle.Create(5,7,4)); geometricFigures.Add(TTriangle.Create(2,6,3)); for geometricFigure in geometricFigures do begin geometricFigure.ToString(); end; finally //geometricFigures.Free(); -> this line is not required (?) end; end;
If I run this code, the geometricFigures list will be automatically freed from memory, even if I do not call the Free method on the list (note the line in the finally block). I expected a different behavior, I thought that the list needed an explicit call to Free (), because the local variable geometricFigures does not use the interface type.
I also noticed that if the list items are not repeated in the inner loop (I temporarily removed it from the code), the list is not freed automatically, and I get a memory leak.
This leads me to the following question: Why is the TObjectList ( geometricFigures ) type list freed up automatically when its elements are iterated, but not if the for-in loop is removed from the code?
Update
I followed Sebastian’s advice and debugged the destructor. List items are destroyed with the following code:
{$REGION 'TList<T>.TEnumerator'} constructor TList<T>.TEnumerator.Create(const list: TList<T>); begin inherited Create; fList := list; fList._AddRef; fVersion := fList.fVersion; end; destructor TList<T>.TEnumerator.Destroy; begin fList._Release; inherited Destroy; // items get destroyed here end;
Update
I had to revise my accepted answer and came to the following conclusion:
In my opinion, Rudy's answer is correct, although the described behavior may not be an error within the framework. I think Rudy makes a good argument, indicating that the structure should work as expected. When I use the for-in loop, I expect this to be a read-only operation. Putting away the list afterwards is not what I expected.
On the other hand, Fritzw and David Heffernan indicate that the design of the Spring4D framework is based on the interface and therefore should be used in this way. While this behavior is documented (perhaps Fritzw can give us a link to the documentation) I agree with David that my use of the framework is incorrect, although I still believe that the framework’s behavior is skipped.
I am not experienced enough in development with Delphi to assess whether the described behavior is actually a mistake or not, so I withdrew my accepted answer, sorry for that.