有哪些技术可以自动释放delphi应用程序中的对象?
使用接口而不是对象.它们被引用计数并在引用计数达到0时自动释放.
我编写了一个函数GC(obj:TObject)(用于Garbage Collect),它接受一个对象并在执行离开当前方法时释放它.它有点像Try Finally Free块的单行速记功能.
代替:
procedure Test; var AQuery: TQuery; begin AQuery := TQuery.Create(nil); try ... finally FreeAndNil(AQuery); end; end;
我只有:
procedure Test; var AQuery: TQuery; begin AQuery := TQuery.Create(nil); GC(AQuery); ... end;
GC函数只是以接口的形式返回一个对象.
function GC(obj: TObject): IGarbo; begin Result := TGarbo.Create(obj); end;
因为TGarbo类来自TInterfacedObject,所以当TGarbo对象超出范围时,它将自动被释放.在TGarbo对象的析构函数中,它还释放了在它的构造函数(您在GC函数中传递的对象)中传递给它的对象.
type IGarbo = interface ['{A6E17957-C233-4433-BCBD-3B53C0C2C596}'] function Obj: TObject; end; TGarbo = class(TInterfacedObject, IGarbo) private FObj: TObject; public constructor Create(AObjectToGC: TObject); destructor Destroy; override; function Obj: TObject; end; { TGarbo } constructor TGarbo.Create(AObjectToGC: TObject); begin inherited Create; FObj := AObjectToGC; end; destructor TGarbo.Destroy; begin if Assigned(FObj) then FreeAndNil(FObj); inherited; end; function TGarbo.Obj: TObject; begin Result := FObj; end;
被困在Delphi 7的世界里,在不久的将来没有升级到带有内置垃圾收集的Delphi版本,我沉迷于使用这种简单的方法来轻松释放本地临时对象!:)
沿着接口,您可以Guard
在JclSysUtils
单元中尝试该功能,这是免费的Jedi代码库的一部分.它允许您将对象与单独的接口引用相关联,因此当该接口引用被销毁时,该对象将随之被销毁.当您无法修改正在使用的类以使其支持自己的接口时,这可能很有用.
var G: ISafeGuard; foo: TStrings; begin // Guard returns TObject, so a type-cast is necessary foo := Guard(TStringList.Create, G) as TStrings; // Use the object as normal foo.Add('bar'); end; // foo gets freed automatically as G goes out of scope
对象和GetMem
分配指针有重载.还有IMultiSafeGuard
,可以确保释放多个对象.
如果您有工厂函数,则可能正在创建对象,设置其某些属性,然后返回它.如果在设置属性时发生异常,您将需要确保释放该对象,因为您无法返回该对象.一种方法是这样的:
function Slurp(const source: TFileName): TStrings; begin Result := TStringList.Create; try Result.LoadFromFile(source); except Result.Free; raise; end; end;
随着Guard
,它会变成这样:
function Slurp(const source: TFileName): TStrings; var G: ISafeGuard; begin Result := Guard(TStringList.Create, G) as TStrings; Result.LoadFromFile(source); G.ReleaseItem; end;
该ReleaseItem
方法撤销ISafeGuard
对象的所有权.如果在发生异常之前发生异常,则当堆栈展开并释放接口时,防护将释放该对象.
我不得不说,我不喜欢"隐藏"一个物体的自由.拥有传统代码要好得多:
MyObject := TObject.Create; try // do stuff finally FreeAndNil(MyObject); end;
它不会出错,按预期工作,人们认识到这种模式.
使用VCL提供的组件的对象所有权.只要您使用非零所有者创建对象,就不需要明确地释放它们.另见我对这个问题的回答.