我有一个关于 Spring4D 框架中 TObjectList 类的行为问题。在我的代码中,我创建了一个几何图形列表,例如 正方形
、圆形
、三角形
,每个几何图形都定义为一个独立的类。为了在列表被销毁时自动释放几何图形,我定义了一个类型为 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;
如果我运行这段代码,即使我没有在列表(注意finally块中被注释的行)上调用
Free
方法,列表geometricFigures
也会自动从内存中释放。我期望有不同的行为,我认为需要显式调用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开发经验不足的我来说,评估所描述的行为是否实际上是一个bug还是不正确的,因此撤销了我的接受答案,非常抱歉。