delphi - 通用树节点结构:释放子节点的问题
问题描述
基于这个GenericTree我已经实现了以下通用树节点结构:
type
TTreeNode<T>=class
private
procedure FreeChildNodes;
procedure RemoveMyselfFromParentChildNodesList;
function GetIndexInParentChildNodesList: Integer;
public
NodeData: T;
ChildNodes: TList<TTreeNode<T>>;
ParentNode: TTreeNode<T>;
constructor Create(const AParentNode: TTreeNode<T>); overload;
destructor Destroy; override;
end;
implementation
constructor TTreeNode<T>.Create(const AParentNode: TTreeNode<T>);
begin
inherited Create;
ParentNode:=AParentNode;
ChildNodes:=TList<TTreeNode<T>>.Create;
end;
destructor TTreeNode<T>.Destroy;
begin
FreeChildNodes;
RemoveMyselfFromParentChildNodesList;
ChildNodes.Free;
inherited;
end;
procedure TTreeNode<T>.FreeChildNodes;
var
i: Integer;
begin
for i := ChildNodes.Count-1 downto 0 do
begin
ChildNodes[i].Free;
end;
ChildNodes.Clear;
end;
function TTreeNode<T>.GetIndexInParentChildNodesList: Integer;
var
i: Integer;
begin
Result:=-1;
if ParentNode<>nil then
begin
Result:=ParentNode.ChildNodes.IndexOf(Self);
end;
end;
procedure TTreeNode<T>.RemoveMyselfFromParentChildNodesList;
begin
if ParentNode<>nil then
begin
ParentNode.ChildNodes.Delete(GetIndexInParentChildNodesList);
end;
end;
这工作正常。
现在我想创建一个具有特定对象类型的后代类。
对象类型为:
type
TMyObject=class
public
Value: string;
constructor Create; override;
destructor Destroy; override;
end;
和新的后代类:
type
TMyTreeNode=class(TTreeNode<TMyObject>)
private
public
constructor Create(const AParentNode: TMyTreeNode); overload;
destructor Destroy; override;
end;
implementation
constructor TMyTreeNode.Create(const AParentNode: TMyTreeNode);
begin
inherited Create(AParentNode);
NodeData:=TMyObject.Create;
end;
destructor TMyTreeNode.Destroy;
begin
NodeData.Free;
inherited;
end;
当我释放TMyTreeNode
带有TMyTreeNode.Destroy
继承TTreeNode<T>.Destroy
的 a 时,会调用以ChildNodes
递归方式释放。问题是所有的子节点都被释放,TTreeNode<T>.Destroy
因此没有TMyObjects
被释放,留下内存泄漏。
我也尝试使用TObjectList
而不是TList
for ChildNodes
。然而,TObjectList
在我释放子节点之前,它似乎会自行破坏。
如何解决这个问题呢?
解决方案
你可以使用:
procedure TTreeNode<T>.FreeChildNodes;
var
i: Integer;
begin
for i := ChildNodes.Count-1 downto 0 do
begin
ChildNodes[i].NodeData.free;
ChildNodes[i].Free;
end;
ChildNodes.Clear;
end;
如果析构函数只影响父类型的字段,则无需重写析构函数。在您的情况下,TMyTreeNode.Destroy
唯一从父级释放 NodeData,因此您最好在TTreeNode<T>.FreeChildNodes
过程中执行此操作。