如何从内存中释放存储在TreeView中的对象?

时间:2019-01-01 23:44:53

标签: object pointers delphi-7 new-operator dispose

我使用Delphi7。我创建了一个存储信息的记录,并使用指针将该记录作为对象存储在包含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;

当我删除TreeView OnDelete事件中的所有项目时,我会得到:

if assigned(Node.Data) then
begin
  Dispose(Node.Data);
end;

我要做的是从内存中释放所有对象!

如果我使用该列表处理所有对象,那么如果我从TreeView中删除任何项目,则会引发无效的指针错误!

即使配置了所有指针,MyRecPtr仍指向内存中的某个位置,Node.Data也指向内存!

1 个答案:

答案 0 :(得分:1)

您的代码崩溃是因为您两次释放相同的内存,因为您尚未定义记录实例的任何明确所有权。

您的apitokenListaDePonteiros列表是多余的,可以删除。 ListaDeObjectos可以是记录的所有者,您可以在TTreeView事件中简单地Dispose()对其进行记录,并对其进行处理 1

TTreeView.OnDeletion

否则,如果您选择保留单独的列表,请保留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列表(因为没有理由维持2个列表跟踪完全相同的值)。您只需要决定是要ListaDePonteiros还是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和{删除单个节点时,{1}}已同步:

Tree1

1。每当您ListaDeObjectos执行记录实例时,请确保将 raw 指针类型转换为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; ,否则编译器将无法正确确定记录的成员,从而泄漏内存。