如何释放记录中的对象? [英] How to free an object which is in a record?

查看:124
本文介绍了如何释放记录中的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我预测会有两种类型的使用:


  1. 用新的替换记录。



    我认为这个用法很容易实现。因为记录是值类型,所以它们被分配复制,我可以重载分配操作符并释放旧记录所拥有的对象。



    编辑: / strong>分配重载不能,这是一个新的信息给我..)


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



    我可以想到一种释放对象的私有方法,并且可以手动调用示波器激励。但是,这里是同样的问题:如何使它更加记录?这种行为感觉像一个类...


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

  TProperties = record 
...其他一些spesific类型字段:整数,指针等。
FBaseData:指针;

FAdditionalData:TList< Pointer> ;;
// FAdditionalData:指针数组;这是第一个定义定义
end;

假设

 code> FAdditionalData:= TList< Pointer> .Crete; 

以记录构造函数或手动方式在记录变量范围内通过公开访问该字段

 程序TFormX.ButtonXClick(发件人:TObject); 
var
rec:TProperties;
begin
//rec:=TProperties.Create(with some parameters);

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

//做某些工作与rec
结束;

退出ButtonClick范围后, rec 不过是一个 TList 仍然保持其内存泄漏的存在...

解决方案

如果您在记录中是一个对象引用,那么你无法得到编译器来帮助你。你对这个物体的一生负责。你不能重载赋值运算符,并且没有得到任何范围定稿的通知。



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

  TMyRecord = record 
obj:TMyObject;
guard:IInterface;
结束

您需要确保 TMyObject 管理其生命周期通过引用计数。例如,从 TInterfacedObject 导出。



当您初始化记录时,您执行此操作:

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

此时, guard 记录将管理您的对象的生命周期。



事实上,如果你想进一步推动这个想法,你可以建立一个专门的类来保护对象的生命周期。那不再限制你在你的课上实现 IInterface 。网络上有很多例子说明了这个技术。例如,我提供了Jarrod Hollingworth的文章,标题为智能指针,以及Barry Kelly的标题为引用计数指针,重新访问。那里还有更多的东西这是一个古老的伎俩!



然而,请注意,您在这里是一个奇怪的价值类型和参考类型的混合。在表面上,记录是价值类型。但是,这个行为就像一个参考类型。如果您在记录中有其他字段是值类型,那么会更混乱。当您处理这样的记录时,您需要非常了解此问题。



从表面上看,不用多了解设计,我会倾向于建议您不要将对象引用放在记录中。它们适合参考类型,即类别。


Here I have a tricky situation, I guess. I need to be able to free an object which is a field of a record. I would normally write the cleanup code in the destructor, if it was a class. But since record types can't introduce a "destructor", how would it be possible to call TObject(Field).Free; ?

There'll be two types of usage I predict:

  1. Replacing the record with a new one.

    I think this usage would be easy to implement. Since records are value types and so they are copied on assignment, I can overload the assigning operator and free the objects owned by old record.

    ( Edit: Assignment overloading wasn't able. That's a new info to me.. )

  2. Exiting the scope where record variable defined.

    I can think of a private method that frees the objects and this method could be called on scope excitation manually. BUT, here is the same question: How to make it more recordly? This behaviour kind of feels like a class...

Here is a sample (and obviously not the intended usage):

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;

Assume,

FAdditionalData:=TList<Pointer>.Crete;

called in record constructor or manually in record variable scope by accessing the field publicly like

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;

After exiting the ButtonClick scope the rec is no more but a TList still keeps its existance which causes to memory leaks...

解决方案

If all you have in the record is an object reference, then you can't get the compiler to help you. You are in sole charge of the lifetime of that object. You cannot overload the assignment operator, and you don't get any notification of scope finalisation.

What you can do though is to add a guard interface that will manage the lifetime of the object.

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

You need to make sure that TMyObject manages its lifetime by reference counting. For example by deriving from TInterfacedObject.

When you initialise the record you do this:

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

At this point, the guard field of the record will now manage your object's lifetime.

In fact, if you want to push this idea further, you can build a dedicated class to guard the lifetime of objects. That then no longer constrains you to implement IInterface on your class. There are plenty of examples on the web that illustrate the technique. For example I offer Jarrod Hollingworth's article titled Smart Pointers, and Barry Kelly's titled Reference-counted pointers, revisited. There are many more out there. It's an old trick!

Note however, that what you have here is a strange hybrid of value type and reference type. On the face of it, records are value types. However, this one acts like a reference type. If you have other fields in the record that are value types then that would be even more confusing. You'll need to be very aware of this issue when you work with such a record.

On the face of it, without knowing more about your design, I'd be inclined to advise you not to put object references in records. They fit better inside reference types, i.e. classes.

这篇关于如何释放记录中的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆