object - 如何从内存中释放存储在 TreeView 中的对象?
问题描述
我使用 Delphi 7。我创建了一个存储信息的记录,并使用指针将该记录作为一个对象存储在具有 100 多个项目的 TreeView 中。
我的问题是,如何从内存中释放或消除所有这些对象?
type
PMyRec = ^TMyRec;
TMyRec = record
Tipo: string;
parent: string;
end;
var
MyRecPtr: PMyRec;
for x := 1 to 100 do
begin
New(MyRecPtr);
MyRecPtr^.Tipo := '1';
MyRecPtr^.parent := 'paul';
Tree1.Items.AddChildObject(nil, IntToStr(x) + '-NewItem', MyRecPtr);
ListaDePonteiros.Add( MyRecPtr ); // I use a TList to store pointers
ListaDeObjectos.Add( MyRecPtr ); // I use a TList to store Objects
end;
我如何尝试将它们全部删除:
procedure TForm1.Button2Click(Sender: TObject);
procedure EmptyTList(Var AList: TList);
var
intContador: integer;
begin
for intContador := (AList.Count-1) downto 0 do
begin
if Assigned(AList.Items[intContador]) then
begin
Dispose(AList.Items[intContador]);
AList.Items[intContador] := nil;
AList.Delete(intContador);
end;
end;
end;
begin
if Assigned(MyRecPtr) then
begin
EmptyTList(ListaDePonteiros);
end;
end;
当我删除 TreeViewOnDelete
事件中的所有项目时,我有这个:
if assigned(Node.Data) then
begin
Dispose(Node.Data);
end;
我想要做的是从内存中释放所有对象!
如果我使用该列表处理所有对象,那么如果我从 TreeView 中删除任何项目,则会引发无效指针错误!
即使处理了所有指针,MyRecPtr
仍然指向内存中的某个位置,而且Node.Data
!
解决方案
您的代码正在崩溃,因为您两次释放相同的内存,因为您没有定义任何明确的记录实例所有权。
您的ListaDePonteiros
和ListaDeObjectos
列表是多余的,可以删除。TTreeView
可以是记录的所有者,您可以在事件中简单地拥有Dispose()
它们TTreeView.OnDeletion
并完成它1。
var
MyRecPtr: PMyRec;
for x := 1 to 100 do
begin
New(MyRecPtr);
try
MyRecPtr^.Tipo := '1';
MyRecPtr^.parent := 'paul';
Tree1.Items.AddChildObject(nil, IntToStr(x) + '-NewItem', MyRecPtr);
except
Dispose(MyRecPtr);
raise;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Tree1.Items.Clear;
end;
procedure TForm1.Tree1Deletion(Sender: TObject; Node: TTreeNode);
begin
if Assigned(Node.Data) then
Dispose(PMyRec(Node.Data));
end;
否则,如果您选择保留一个单独的列表,请保留该ListaDeObjectos
列表并删除该ListaDePonteiros
列表(因为没有理由维护 2 个跟踪完全相同的值的列表)。您只需要决定是否想要ListaDeObjectos
或Tree1
拥有您分配的记录:
如果
ListaDeObjectos
要成为所有者,请不要Dispose(Node.Data)
在TTreeView.OnDeletion
活动中致电。var MyRecPtr: PMyRec; Idx: Integer; for x := 1 to 100 do begin New(MyRecPtr); try MyRecPtr^.Tipo := '1'; MyRecPtr^.parent := 'paul'; Idx := ListaDeObjectos.Add(MyRecPtr); try Tree1.Items.AddChildObject(nil, IntToStr(x) + '-NewItem', MyRecPtr); except ListaDeObjectos.Delete(Idx); raise; end; except Dispose(MyRecPtr); end; end; procedure TForm1.Button2Click(Sender: TObject); procedure EmptyTList(AList: TList); var intContador: integer; begin for intContador := 0 to (AList.Count-1) do Dispose(PMyRec(AList[intContador])); AList.Clear; end; begin Tree1.Items.Clear; EmptyTList(ListaDePonteiros); end;
如果
Tree1
要成为所有者,请不要打电话(Dispose(AList.Items[intContador])
实际上EmptyTList()
,您可以完全摆脱EmptyTList()
并在需要时打电话ListaDeObjectos.Clear()
)。var MyRecPtr: PMyRec; Node: TNode; for x := 1 to 100 do begin New(MyRecPtr); try MyRecPtr^.Tipo := '1'; MyRecPtr^.parent := 'paul'; Node := Tree1.Items.AddChildObject(nil, IntToStr(x) + '-NewItem', MyRecPtr); except Dispose(MyRecPtr); raise; end; try ListaDePonteiros.Add(MyRecPtr); except Node.Free; raise; end; end; procedure TForm1.Button2Click(Sender: TObject); begin ListaDePonteiros.Clear; Tree1.Items.Clear; end; procedure TForm1.Tree1Deletion(Sender: TObject; Node: TNode); begin if Assigned(Node.Data) then Dispose(PMyRec(Node.Data)); end;
无论哪种方式,当不进行大规模清理时Tree1
,请考虑在删除单个节点时ListaDeObjectos
调用事件以保持和同步:ListaDeObjectos.Remove()
TTreeView.OnDeletion
Tree1
ListaDeObjectos
procedure TForm1.Tree1Deletion(Sender: TObject; Node: TNode);
begin
if Assigned(Node.Data) then
begin
// only if the TreeView is the owner...
Dispose(PMyRec(Node.Data));
ListaDeObjectos.Remove(Node.Data);
end;
end;
1. 每当您执行Dispose()
记录实例时,请确保您对原始指针进行类型转换PMyRec
,否则编译器将无法正确完成记录的成员,从而导致内存泄漏。
推荐阅读
- java - 如何使我的这部分代码在 java 中可扩展
- node.js - 如何在单个 digitalocean vps 服务器中服务多个节点应用程序?
- java - 在 windows 中,如何在不提及任何特定端口的情况下启动 appium 服务器并利用可用的空闲端口?
- angular - Angular 6中嵌套FormArray中的patchValue
- java - 使用java字节码编辑器追加行后缺少'while'语句
- java - Java:我无法在 while 循环中打印到文本文件,尽管能够在 while 循环之前这样做
- r - 带有负值的条形图上的水平标准误差条
- pytorch - 使用索引张量选择张量的第二个暗淡
- mongodb - 无法序列化类 org.springframework.data.mongodb.core.geo.GeoJsonPoint
- php - 如何防止用户在已经登录时访问登录页面?