处理添加到TStringList的对象

时间:2018-09-21 17:15:14

标签: delphi

我正确吗?
我用在填充过程中创建的记录填充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.

我正在使用Delphi 10.1。

我还想知道清除StringList会发生什么。它会丢弃对象吗?

1 个答案:

答案 0 :(得分:4)

您至少可以通过三种方式处理此问题:

1。手动处理记录

由于您要存储记录的指针,而不是TObject个后代,因此您不能依赖OwnsObjects。将其设置为False

Free TStringList之前,您应该手动Dispose记录每条记录:

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

请注意,对PUsageData的强制转换对于Dispose的正常运行很重要。

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

VarUsages.Free;

请注意,Dispose将妥善完成记录的定案,包括其中的字符串。

注意:正如David Heffernan所说: 以及在销毁字符串列表时手动销毁,每当删除或修改项目时都必须这样做< / em>。这使另两个选择更具吸引力,IMO。

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

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

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

然后,您可以将OwnsObjects设置为True,并让字符串列表来释放它们。该方案也适用于ARC受管目标。使用New代替Rec := TUsageData.Create;。据我所知,您可以使用相同的代码。

3。不使用TStringList

请使用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); 本身以外,不需要释放任何东西。释放它也将需要完成其中的记录。

git