我可以在class
不释放它们的情况下扔掉 es,还是我的软件会开始泄漏?
例如我可以这样做吗
Engine := TEngine.Create(TV);
然后摆脱引用没有任何问题,还是我必须先调用它的Free
方法?
或者有一个返回 aTSomething
而不必稍后释放它的引用的函数?
我可以在class
不释放它们的情况下扔掉 es,还是我的软件会开始泄漏?
例如我可以这样做吗
Engine := TEngine.Create(TV);
然后摆脱引用没有任何问题,还是我必须先调用它的Free
方法?
或者有一个返回 aTSomething
而不必稍后释放它的引用的函数?
一般规则是,如果你创建它,你应该释放它。最好的方法是尝试..finally 如果您在代码中创建它:
var
Engine: TEngine;
begin
Engine := TEngine.Create(TV);
try
// Do stuff with Engine
finally
Engine.Free;
end;
end;
例外情况是,如果您有一个接受所有者作为参数的对象(例如类似的可视控件TEdit
或 的非可视后代TComponent
)。如果您分配所有者,它将在所有者被释放时释放它。(如果您在没有所有者的情况下创建它,您仍然必须自己释放它。)
procedure TForm1.FormCreate(Sender: TObject);
var
EditA, EditB: TEdit;
begin
EditA := TEdit.Create(Self); // You're passing the form as owner; don't free
EditB := TEdit.Create(nil); // Creating without an owner; you free.
end;
如果该类是另一个对象的成员(字段),则在包含对象中创建它并在其中constructor
释放它destructor
:
type
TOuterClass = class(TObject)
private
FEngine: TEngine;
public
constructor Create;
destructor Destroy; override;
end;
implementation
constructor TOuterClass.Create;
begin
inherited;
FEngine := TEngine.Create(TV);
end;
destructor TOuterClass.Destroy;
begin
FEngine.Free;
inherited;
end;
从技术上讲,是的,您使用构造函数初始化的所有内容都必须显式释放。
但是有一些简单的解决方法,如果使用得当,可以为您省去大部分麻烦:
1:使用 TInterfacedObject:
IMyStuff = interface(IUnknown)
['{9DF82155-2475-4403-8933-969DC4912AD7}']
function Print:boolean;
procedure DoStuff;
end;
TMyStuff = class(TInterfacedObject, IMyStuff)
private
function Print:boolean;
procedure DoStuff;
end;
像任何其他类一样实现 TMyStuff。但是,当您在代码中使用该类时,请使用 IMyStuff 类型的变量,如下所示:
procedure MyIProcedure;
var myStuff: IMyStuff;
begin
myStuff:=TMyStuff.create;
myStuff.DoStuff;
end;
无需在 'TMyStuff.create' 调用中进行强制转换(在这种情况下 - 有时是......) - 因为变量是 IMystuff 类型,所以这是隐式的。不需要释放 IMyStuff (事实上你不能,虽然你可以调用 IMyStuff:=nil。)因为它被声明为接口类型,自动垃圾收集是使用 COM 引用计数模型实现的 - Delphi 为你处理这个当您从 TInterfacedObject 继承时。
但是不要混合类类型变量:即 TMyStuff 与 IMyStuff 变量类型。这可能会导致一些令人讨厌的混乱和错误,让您摸不着头脑。这就是我通常将 TInterfacedObject 的成员声明为PRIVATE的原因,就像我在这里所做的那样,通过对 TMyStuff 的引用使它们无法访问。但是,它们可以通过对 IMyStuff 的引用来访问:根据定义,所有接口成员都是公共的。
2:除了 Ken 的出色回答之外,VCL 的 TObjectList 和 TObjectDictionary 为它们包含的所有对象引用提供了自动垃圾收集(有关详细信息,请参阅 Delphi 文档) - 但它们本身必须被释放,然后其余的被释放。
只要在 TInterfacedObject 的析构函数中释放 ObjectList 或 ObjectDictionary,在 TInterfacedObject 中使用 TObjectList 或 TObjectDictionary 就不必再担心垃圾回收了。当 referenceCount=0 时,Delph 的实现将自动调用该析构函数。