Object Pascal:必须释放所有对象(类)吗?

时间:2013-04-13 23:27:34

标签: oop pascal freepascal delphi

我是否可以在不释放它们的情况下抛弃class es,或者我的软件是否会开始泄漏泄漏?

例如,我可以这样做吗

Engine := TEngine.Create(TV);

然后没有任何问题摆脱引用,或者我必须先调用它的Free方法吗?

或者有一个函数返回TSomething而不必在以后释放它的引用?

2 个答案:

答案 0 :(得分:2)

一般规则是,如果你创建它,你应该释放它。最好的方法是尝试..如果你在代码中创建它:

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 :(得分:1)

从技术上讲,是的,必须明确释放使用构造函数初始化的所有内容。

但有一些简单的解决方法,如果使用得当,可以为您节省大部分麻烦:

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中使用TObjectList或TObjectDictionary,只要在TInterfacedObject的析构函数中释放ObjectList或ObjectDictionary,就再也不用担心垃圾回收了。当referenceCount = 0时,Delph的实现将自动调用析构函数。