delphi - 处理添加到 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 时会发生什么。它会处理对象吗?
解决方案
你至少有三种方法来处理这个问题:
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 评论的那样:不要忘记,除了在字符串列表被销毁时手动处理之外,无论何时删除或修改 item 都必须这样做。这使得其他两个选项更具吸引力,IMO。
2.使用对象(类实例)代替记录
或者,您可以TUsageData
变成一个简单的类(没有方法,没有属性,只有公共字段):
type
TUsageData = class
public
DeclaredIn: string;
LineNumber: Integer;
TotalUsage: Integer;
end;
然后您可以设置OwnsObjects
并True
让字符串列表负责释放它们。这种情况也适用于 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);
推荐阅读
- c++ - 在他的调用者完成工作后线程会死吗?
- r - 有条件地将 NA 替换为其他行中的值
- r - 根据多个条件对字符串进行子集化
- highcharts - Highcharts 柱形图中的向下钻取事件
- python - Paramiko 在使用“sftp.file/open”的脚本末尾引发“TypeError:不允许捕获不从 BaseException 继承的类”
- symfony - ParamConverter Symfony 中的集合
- sendgrid - Mailjet/Sendgrid:发送正文中带有冒号的电子邮件显示“无内容”
- swift - swift5 - 枚举协议 - 自我和自我以及一个变量
- c# - EF 嵌套/非嵌套上下文处理和解决方案
- php - 命令到处理程序以在 DDD 和 CQRS 中聚合根到存储库流