而_Finalize方法是做對有類型的指針(如:PGUID)所指向的結構體變量的一些“善後工作”,如果為純Pointer,_Finalize方法內將不執行:
asm
{ ECX number of elements of that type }
CMP ECX, 0 { no array -> nop }
JE @@zerolength
...
@@zerolength:
end;
所以,我們就可以放心的使用Dispose方法了:
if fTypeInfo = nil then
//FreeMem(Pointer((@fObj)^))
// 此處應該調用Dispose,因為Dispose內部已經實現FreeMem:
// PUSH EAX
// CALL _Finalize
// POP EAX
// CALL _FreeMem
Dispose(Pointer((@fObj)^));
四、改進New方法
在方法New中,我們將指針傳入智能指針內部,由智能指針來管理指針的自動釋放。在翻譯Java的JSon-RPC的時候,為了實現類似於Java的垃圾回收功能,我使用到了智能指針。當翻譯到JSONObject的時候,我發現New方法非常的麻煩:
fMyHashMap:=TAutoPtr<TDictionary<string,IAutoPtr<TObject>>>.New(TDictionary<string,IAutoPtr<TObject>>.Create);
我已經告訴TAutoPtr<T>,T的類型為TDictionary<string,IAutoPtr<TObject>>,我能不能寫一個New的重載方法,讓它自動實現對T的創建呢?如果T的約束為T: class或T: constructor,則很好實現:T.Create即可。現在,T沒有任何約束,如果加了T.Create編譯器是不支持的。我研究出了一種可行的方法,代碼如下:
class function TAutoPtr<T>.New: IAutoPtr<T>;
var
typInfo: PTypeInfo;
obj: TObject;
objNew: T;
begin
typInfo := TypeInfo(T);
// 在此處只能創建class型的指針,不能創建無類型指針
// 因為指針在Delphi中有兩種初始化方式
// 1、GetMem(p, 100);
// 2、New(p);
if (typInfo <> nil) and (typInfo.Kind = tkClass) then
begin
// 獲取T的類型並調用默認構造函數創建對象
obj := GetTypeData(typInfo).ClassType.Create;
// 使用以下方法強制轉換
objNew := T((@obj)^);
Exit(New(objNew));
end;
raise Exception.Create('只能構造class型的對象。');
end;
原理在代碼的注釋中寫得很清楚了,這裡只能針對class型的類型做構造,Pointer型的類型會拋出異