運行失敗了,原因是在DoTestAutoPtr方法退出了以後,TAutoPtr<TTestClass>.New(TTestClass.Create(10))語句所創建的接口引用計數為0,此時它會調用TTestClass的Destroy方法將fList銷毀。此時,我們調用DoPrintInt方法,想得到fList第一個元素,但是fList本身已經被銷毀了,所以導致錯誤的發生。
我們將第6*行改為:
gTt:=TAutoPtr<TTestClass>.New(TTestClass.Create(10)).Release;
運行結果:
此時不會出現錯誤,因為Release方法已經通知智能指針堆對象已經不受智能指針管理,所以在TAutoPtr<TTestClass>銷毀的時候不會調用 TTestClass的析構函數,fList得以保留下來。
在此處我們可以看到,由於堆對象不再受到智能指針的管理,所以我們必須手動的將其釋放FreeAndNil(gTt),否則就會產生上圖所發生的結果:內存洩露。
八、總結
剛開始實現棧對象我考慮過使用record,Delphi的record非常類似於類,保存在棧中,支持方法、屬性和帶參數的構造函數,但是不支持析構函數,所以沒有辦法實現我們的智能指針。Delphi版的智能指針很早就在cnPack討論區中有前輩提出來過了(http://bbs.cnpack.org/vIEwthread.PHP?tid=1399),但是使用起來不方便導致這種寫法不怎麼流行。自從D2009支持泛型以後,以前很多實現起來很麻煩的功能現在都能很簡單的實現,如智能指針與泛型集合的結合。但是,在Delphi中使用智能指針是稍微有一些性能損失的,在目前電腦速度越來越快的今天,這點損失已經顯得微不足道了。
本文配套源碼