我对 Spring4D 框架的 TObjectList 类的行为有疑问。在我的代码中,我创建了一个几何图形列表,例如square
, circle
, triange
,每个都定义为一个单独的类。为了在列表被破坏时自动释放几何图形,我定义了一个 TObjectList 类型的列表,如下所示:
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;
如果我运行此代码,geometricFigures
即使我没有调用Free
列表上的方法,列表也会自动从内存中释放(注意 finally 块中的注释行)。我预计会有不同的行为,我认为列表需要显式调用 Free() 因为局部变量geometricFigures
没有使用接口类型。
我进一步注意到,如果列表的项目没有在 for-in 循环中迭代(我暂时从代码中删除了它),则列表不会自动释放并且我会出现内存泄漏。
这使我想到以下问题:为什么 TObjectList ( geometricFigures
) 类型的列表在其项目被迭代时会自动释放,但如果从代码中删除 for-in 循环则不会?
更新
我听从了 Sebastian 的建议并调试了析构函数。列表项被以下代码破坏:
{$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;
更新
我不得不重新考虑我接受的答案并得出以下结论:
在我看来,Rudy 的回答是正确的,即使所描述的行为可能不是框架中的错误。我认为 Rudy 提出了一个很好的论点,他指出框架应该按预期工作。当我使用 for-in 循环时,我希望它是一个只读操作。之后清除列表不是我所期望的。
另一方面,Fritzw 和 David Heffernan 指出 Spring4D 框架的设计是基于接口的,因此应该以这种方式使用。只要记录了这种行为(也许 Fritzw 可以给我们参考文档),我同意 David 的观点,即我对框架的使用是不正确的,即使我仍然认为框架的行为具有误导性。
我在使用 Delphi 开发方面没有足够的经验来评估所描述的行为是否实际上是一个错误,或者没有因此撤销我接受的答案,对此感到抱歉。