delphi 如何释放记录中的对象?

92dk7w1h  于 2022-12-03  发布在  其他
关注(0)|答案(3)|浏览(181)

这里我遇到了一个棘手的情况。我需要释放一个对象,它是一个记录的字段。如果它是一个类,我通常会在析构函数中编写清理代码。但是由于记录类型不能引入“析构函数”,怎么可能调用TObject(Field).Free;
我预计会有两种使用方式:
1.将记录替换为新记录。
我认为这种用法很容易实现。因为记录是值类型,所以它们在赋值时被复制,我可以重载赋值运算符并释放旧记录所拥有的对象。
编辑:无法进行赋值重载。这对我来说是一个新信息。)
1.正在退出定义记录变量的范围。
我可以想到一个释放对象的私有方法,这个方法可以在作用域激发时手动调用。但是,这里有同样的问题:如何使它更
记录
?这种行为有点像一个类...
下面是一个示例(显然不是预期的用法):

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;

假设,

FAdditionalData:=TList<Pointer>.Crete;

在记录构造函数中调用,或通过访问字段(如

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;

退出ButtonClick作用域后,rec不再存在,但TList仍然存在,这导致内存泄漏...

zi8p0yeb

zi8p0yeb1#

如果记录中只有一个对象引用,那么编译器就不能帮你了。你要全权负责这个对象的生存期。你不能重载赋值操作符,也不会得到任何作用域结束的通知。
不过,您可以添加一个guard接口来管理对象的生存期。

TMyRecord = record
  obj: TMyObject;
  guard: IInterface;
end;

您需要确保TMyObject通过引用计数来管理其生存期。例如,通过从TInterfacedObject派生。
初始化记录时,请执行以下操作:

rec.obj := TMyObject.Create;
rec.guard := rec.obj;

此时,记录的guard字段将管理对象的生存期。
事实上,如果你想进一步推广这个想法,你可以构建一个专用的类来保护对象的生存期。这样你就不再需要在类上实现IInterface了。网上有很多例子来说明这个技术。例如,我提供了Jarrod Hollingworth的文章,标题为Smart Pointers。巴里Kelly的标题是Reference-counted pointers, revisited。还有很多。这是一个老把戏!
但是请注意,这里的记录是值类型和引用类型的奇怪混合。从表面上看,记录是值类型。但是,这个记录的行为类似于引用类型。如果记录中的其他字段是值类型,那么这将更加令人困惑。在处理这样的记录时,您需要非常注意这个问题。
从表面上看,在不了解你的设计的情况下,我倾向于建议你不要把对象引用放在记录中,它们更适合放在引用类型中,也就是类中。

carvr3hs

carvr3hs2#

我记得有人创建了一个名为TLifetimeWatcher的类。基本上,它看起来像:

TLifetimeWatcher = class(TInterfacedObject)
private
  fInstance: TObject;
  fProc: TProc; 
public
  constructor Create(instance: TObject); overload;
  constructor Create(instance: TObject; proc: TProc); overload;
  destructor Destroy; override;
end;

//(cleanup)proc将在解构函式中执行(如果已指派),否则会叫用Free方法来释放执行严修。

pwuypxnk

pwuypxnk3#

https://docwiki.embarcadero.com/RADStudio/Sydney/en/Custom_Managed_Records

THeaderStruct = record
  private

  public
    class operator Initialize (out Header: THeaderStruct);
    class operator Finalize (var Header: THeaderStruct);
end;

相关问题