七、注意事項
1、智能指針與堆對象之間的循環引用
假如我們把TTestClass類進行如下修改,讓堆對象擁有指向它智能指針的引用:
TTestClass = class
private
fInt: Integer;
fAp: IAutoPtr<TTestClass>;
public
constructor Create(aInt: Integer); overload; virtual;
destructor Destroy; override;
procedure DoPrintInt;
property Ap: IAutoPtr<TTestClass> read fAp write fAp;
end;
同時,把測試方法進行如下修改:
procedure DoTestAutoPtr;
var
tt: TTestClass;
ap: IAutoPtr<TTestClass>;
begin
ap := TAutoPtr<TTestClass>.New(TTestClass.Create(10));
tt := ap.Get;
tt.Ap := ap; // 5*
tt.DoPrintInt;
end;
此時,我們得到了非常不靠譜的結果:
智能指針竟然沒有自動釋放!
從上面的分析和前面的代碼我們可以看到,接口的引用計數為0的時候,接口會自動釋放,我們要保證接口能夠被順利的釋放,必須保證接口的引用計數為0。
從第 5* 點代碼我們可以看到,tt.Ap := ap,使得智能指針與堆對象之間進行了循環引用,導致接口ap的引用計數+1為2。最後在方法退出的時候,雖然ap占用的引用已經被釋放了,引用-1,但是由於堆對象tt不會自己釋放,所以堆對象tt.Ap所占用的引用沒有釋放,方法在退出時,接口的引用數為1,接口沒有自動釋放。