首页 > 解决方案 > 处理添加到 TStringList 的对象

问题描述

我这样做对吗?
我正在使用在填充期间创建的记录填充 TStringlist 中的对象。我已将 TStringList.OwnsObjects 设置为 true。但是,当我关闭应用程序时,我会遇到访问冲突。下面是我的代码的摘录。

type
  PUsageData = ^TUsageData;
  TUsageData = record
    DeclaredIn: String;
    LineNumber: Integer;
    TotalUsage: Integer;
  end;

...

var VarUsages: TStringList;    // object contains a TUsageData record


procedure BuildUsageList;
var idx, idy, n,m: Integer;
    sl: TStringList;
    s,t: String;
    rec: PUsageData;
begin
  VarUsages.Clear;
  sl:= TStringList.Create;
  s := '';
  // First make a list and create a record for each variable declared in program
  for idx := 0 to IncludeList.Count -1 do begin
    GetSource(IncludeList[idx], sl);
    for idy := 0 to sl.Count -1 do begin
      t := '';
      t := CodeAnalyser.GetItems(sl[idy], caVariables);
      if t > '' then begin
        system.New(Rec);
        rec.DeclaredIn := IncludeList[idx];
        rec.LineNumber := idy;
        rec.TotalUsage := 0;
        VarUsages.AddObject(t, TObject(rec));
      end;
    end;
  end;
end;

...

initialization
  VarUsages := TStringList.Create;
  VarUsages.OwnsObjects := true;

finalization
  VarUsages.Free;
end.

我正在使用德尔福 10.1。

我也想知道当我清除 StringList 时会发生什么。它会处理对象吗?

标签: delphi

解决方案


你至少有三种方法来处理这个问题:

1. 手动处理记录

因为您正在存储指向记录的指针,而不是TObject后代,所以您不能依赖OwnsObjects. 设置为False

在你之前FreeTStringList你应该手动Dispose的每条记录:

for I := 0 to VarUsages.Count - 1 do
  Dispose(PUsageData(VarUsages.Objects[i]));

请注意,强制转换对于正常工作PUsageData很重要。Dispose

因为您设置OwnsObjectsFalse,字符串列表不会尝试释放“对象”,因此您可以立即调用:

VarUsages.Free;

请注意,这Dispose将负责正确完成记录,包括里面的字符串。

注意:正如 David Heffernan 评论的那样:不要忘记,除了在字符串列表被销毁时手动处理之外,无论何时删除或修改 item 都必须这样做。这使得其他两个选项更具吸引力,IMO。

2.使用对象(类实例)代替记录

或者,您可以TUsageData变成一个简单的类(没有方法,没有属性,只有公共字段):

type
  TUsageData = class
  public
    DeclaredIn: string;
    LineNumber: Integer;
    TotalUsage: Integer;
  end;

然后您可以设置OwnsObjectsTrue让字符串列表负责释放它们。这种情况也适用于 ARC 托管目标。而不是New,您使用Rec := TUsageData.Create;. 据我所知,您可以使用相同的代码。

3.不使用TStringList

代替字符串列表,使用类似 a 的东西TList<TUsageData>,其中TUsageData可以保留记录。无需使用指针。只需将t字符串也放入记录中。由于您正在处理记录,因此不需要释放任何东西,当然除了TList<>它本身。释放它也将负责最终确定其中的记录。

  Rec: TUsageData; // record!
  ...
  t := CodeAnalyser.GetItems(sl[idy], caVariables);
  if t > '' then 
  begin
    Rec.t := t;
    Rec.DeclaredIn := IncludeList[idx];
    Rec.LineNumber := idy;
    Rec.TotalUsage := 0;
    VarUsages.Add(Rec);

推荐阅读