如何释放记录中的对象?

The*_*iEn 9 delphi record

我猜这里有一个棘手的情况.我需要能够释放一个记录字段的对象.我通常会在析构函数中编写清理代码,如果它是一个类.但是由于记录类型不能引入"析构函数",如何调用TObject(Field).Free;

我预测会有两种用法:

  1. 用新的记录替换记录.

    我认为这种用法很容易实现.由于记录是值类型,因此它们在赋值时被复制,我可以重载赋值运算符并释放旧记录所拥有的对象.

    (编辑:分配重载不能.这对我来说是个新信息..)

  2. 退出记录变量定义的范围.

    我可以想到一个释放对象的私有方法,这个方法可以手动调用范围激励.但是,这是同一个问题:如何使它更具记录性?这种行为感觉就像一个班级......

这是一个示例(显然不是预期用途):

TProperties = record
  ... some other spesific typed fields: Integers, pointers etc..
  FBaseData: Pointer;

  FAdditionalData: TList<Pointer>;
  //FAdditionalData: array of Pointer; this was the first intended definition
end;
Run Code Online (Sandbox Code Playgroud)

假设,

FAdditionalData:=TList<Pointer>.Crete;
Run Code Online (Sandbox Code Playgroud)

通过公开访问字段,在记录构造函数中调用或在记录变量范围内手动调用

procedure TFormX.ButtonXClick(Sender: TObject);
var
  rec: TProperties;
begin
  //rec:=TProperties.Create(with some parameters);

  rec.FAdditionalData:=TList<Pointer>.Create;

  //do some work with rec
end;
Run Code Online (Sandbox Code Playgroud)

在退出ButtonClick范围后,rec不再是,但TList仍然保持其存在,导致内存泄漏...

Dav*_*nan 11

如果记录中的所有内容都是对象引用,那么您无法让编译器帮助您.您完全负责该对象的生命周期.您不能重载赋值运算符,也不会获得范围终结的任何通知.

您可以做的是添加一个可以管理对象生命周期的保护接口.

TMyRecord = record
  obj: TMyObject;
  guard: IInterface;
end;
Run Code Online (Sandbox Code Playgroud)

您需要确保TMyObject通过引用计数来管理其生命周期.例如,通过派生而来TInterfacedObject.

初始化记录时,您执行以下操作:

rec.obj := TMyObject.Create;
rec.guard := rec.obj;
Run Code Online (Sandbox Code Playgroud)

此时,guard记录的字段现在将管理对象的生命周期.

实际上,如果你想进一步推动这个想法,你可以构建一个专用的类来保护对象的生命周期.然后,这不再限制您IInterface在课堂上实施.网上有很多例子说明了这种技术.例如,我提供了Jarrod Hollingworth的文章,名为Smart Pointers,以及Barry Kelly的标题为Reference-counting指针,重新审视.那里还有很多.这是一个老技巧!

但请注意,您在此处拥有的是值类型和引用类型的奇怪混合.从表面上看,记录是价值类型.但是,这个就像一个引用类型.如果记录中有其他字段是值类型,那么这将更加令人困惑.使用此类记录时,您需要非常了解此问题.

从表面上看,在不了解您的设计的情况下,我倾向于建议您不要将对象引用放在记录中.它们更适合引用类型,即类.

  • 我建议先用最后一段引导.如果一个人对生命周期管理不是非常非常小心,那么将类放在记录中是快速编写错误代码的途径. (7认同)