【问题标题】:replace an object in a TObjectList with freeing it (Delphi7)用释放它替换 TObjectList 中的对象(Delphi7)
【发布时间】:2017-07-06 16:47:57
【问题描述】:

我有一个元素很少的 TObjectList。我必须在同一个项目中用一个新的替换其中一个(不改变计数)。我执行以下操作:

procedure TForm1.Button1Click(Sender: TObject);
var
  TObj: TObjectList;
  LPoint: TPPoint;
  i: integer;
begin
  TObj:= TObjectList.Create;
  try

    for i:= 0 to 3 do
    begin
        LPoint:= TPPoint.Create(i, i+ 1);
      TObj.Add(LPoint);
    end;

    LPoint:= TPPoint.Create(21, 22);
    TObj.Items[1]:= nil;
    TObj.Items[1]:= LPoint;

    for i:= 0 to 3 do
    begin
        ShowMessage(IntToStr(TPPoint(TObj.Items[i]).X));
    end;

  finally
    TObj.Free;
  end;
end;

我的问题是:如何释放内存中被替换的元素?帮助说“如果他的索引将被重新分配,一个 Objekt 将被释放”。命令TObj.Items[1]:= nil;够了吗?

提前感谢您提供任何信息。

【问题讨论】:

  • 如果我理解正确,文档说 TObj.Items[1]:= LPoint;就够了,不用赋值给nil。

标签: delphi tobjectlist


【解决方案1】:
TObj.Items[1]:= nil;
TObj.Items[1]:= LPoint;

在这里您执行了两项作业,因此班级尝试释放两个项目。

TObj.Items[1]:= nil;

此时,上一项是在您之前的循环中添加的非零引用。该对象因此被销毁。

TObj.Items[1]:= LPoint;

当这一行执行时,TObj.Items[1] = nil 和Free 方法在nil 上被调用。什么都没有发生。

底线是您的代码过于复杂。你可以替换

TObj.Items[1]:= nil;
TObj.Items[1]:= LPoint;

与

TObj.Items[1]:= LPoint;

该类将销毁当前存储在TObj.Items[1] 中的对象,然后将其替换为LPoint。随心所欲。

【讨论】:

    【解决方案2】:

    当使用 OwnsObjects = true (默认行为)创建时,TObjectList.Create() 负责其项目内存管理

    我使用 Delphi XE7 对其进行了测试,因此我不能保证这与 Delphi 7 中的行为完全相同。例如,声明 TObj: TObjectList 没有指定类型是不可能的(不会编译)。

    我使用 TLabel 而不是 TPPoint,并重命名了变量以减少混乱。为了确保它被释放,我将 ReportMemoryLeaksOnShutdown := True 添加到我的 dpr。绝对必须确保您不会弄乱内存。遗憾的是它出现在 Delphi 2006 中,因此在 Delphi 7 中不可用。

    此代码替换列表中的一个项目而没有任何内存泄漏:

    procedure TForm3.Button1Click(Sender: TObject);
    var
      list: TObjectList<TLabel>;
      listItem: TLabel;
      i: integer;
    begin
      list:= TObjectList<TLabel>.Create();
      try
    
        for i:= 0 to 3 do
        begin
            listItem:= TLabel.Create(nil);
            listItem.Caption := 'list item ' + IntToStr(I);
            list.Add(listItem);
        end;
    
        listItem:= TLabel.Create(nil);               
        listItem.Caption := 'list item replaced';
        list.Items[1]:= listItem;
    
        for i:= 0 to 3 do
        begin
            ShowMessage(list.Items[i].Caption);
        end;
      finally
        list.Free;
      end;
    end;
    

    【讨论】:

    • FWIW,如果你在 Delphi 7 中使用 FastMM(你应该使用它,因为它比 borlandmm 好得多),那么你可以使用ReportMemoryLeaksOnShutdown。
    • @DavidHeffernan 我不知道可以这样做。感谢您的信息。
    猜你喜欢
    • 2020-06-26
    • 2011-09-24
    • 2011-10-28
    • 1970-01-01
    • 2010-11-29
    • 2021-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多