这里我遇到了一个棘手的情况。我需要释放一个对象,它是一个记录的字段。如果它是一个类,我通常会在析构函数中编写清理代码。但是由于记录类型不能引入“析构函数”,怎么可能调用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仍然存在,这导致内存泄漏...
3条答案
按热度按时间zi8p0yeb1#
如果记录中只有一个对象引用,那么编译器就不能帮你了。你要全权负责这个对象的生存期。你不能重载赋值操作符,也不会得到任何作用域结束的通知。
不过,您可以添加一个guard接口来管理对象的生存期。
您需要确保
TMyObject
通过引用计数来管理其生存期。例如,通过从TInterfacedObject
派生。初始化记录时,请执行以下操作:
此时,记录的
guard
字段将管理对象的生存期。事实上,如果你想进一步推广这个想法,你可以构建一个专用的类来保护对象的生存期。这样你就不再需要在类上实现
IInterface
了。网上有很多例子来说明这个技术。例如,我提供了Jarrod Hollingworth的文章,标题为Smart Pointers。巴里Kelly的标题是Reference-counted pointers, revisited。还有很多。这是一个老把戏!但是请注意,这里的记录是值类型和引用类型的奇怪混合。从表面上看,记录是值类型。但是,这个记录的行为类似于引用类型。如果记录中的其他字段是值类型,那么这将更加令人困惑。在处理这样的记录时,您需要非常注意这个问题。
从表面上看,在不了解你的设计的情况下,我倾向于建议你不要把对象引用放在记录中,它们更适合放在引用类型中,也就是类中。
carvr3hs2#
我记得有人创建了一个名为TLifetimeWatcher的类。基本上,它看起来像:
//(cleanup)proc将在解构函式中执行(如果已指派),否则会叫用Free方法来释放执行严修。
pwuypxnk3#
https://docwiki.embarcadero.com/RADStudio/Sydney/en/Custom_Managed_Records