一、弊端
在此先要感謝網友裝配腦袋的提醒,在我關於Delphi中實現智能指針的第一篇文章“Delphi2009初體驗 - 語言篇 - 智能指針的實現”裡,裝配腦袋給我提出了這麼個問題:
“管這個叫智能指針未免名不副實了一點,實際上class型的對象引用與指針的語義有跟大的不同。而C++的智能指針就是為了在語義上獲得方便性的一種機制。 ”
後來我想了想,確實存在裝配腦袋所表述的問題。在原來的代碼中,我進行了如下約束:
IAutoPtr<T:class>=interface(IInterface)
我將T類型規定為必須為一個類類型(class型),如果使用TAutoPtr包囊class型的TObject,那麼TAutoPtr只能算是一個“智能對象”,而不是“智能指針”。在此,我們把T: class的約束class去掉,此處就能傳入非class型的類型了,當然也包括指針類型。
二、提出問題
然而,把約束: class去掉,會帶來一些問題:
首先貼出原來的代碼:
1 type
2 IAutoPtr<T: class> = interface(IInterface)
3 ['{BD098FDB-728D-4CAC-AE40-B12B8B556AD3}']
4 function Get: T;
5 function Release: T;
6 procedure Reset(aObj: T);
7 end;
8
9 TAutoPtr<T: class> = class(TInterfacedObject, IAutoPtr<T>)
10 private
11 fObj: T;
12 public
13 class function New(aObj: T): IAutoPtr<T>;
14 constructor Create(aObj: T); virtual;
15 destructor Destroy; override;
16 function Get: T;
17 function Release: T;
18 procedure Reset(aObj: T);
19 end;
20
21 implementation
22
23 { TAutoPtr<T> }
24
25 constructor TAutoPtr<T>.Create(aObj: T);
26 begin
27 fObj := aObj;
28 end;
29
30 class function TAutoPtr<T>.New(aObj: T): IAutoPtr<T>;
31 begin
32 Result := TAutoPtr<T>.Create(aObj) as IAutoPtr<T>; // 注意:此處如果不加as IAutoPtr<T>,程序運行時會報錯,第一次我沒有加as IAutoPtr<T>程序運行一切正常,到後面就不行了,不知道是為什麼
33 end;
34
35 function TAutoPtr<T>.Release: T;
36 begin
37 Result := fObj;
38 fObj := nil;
39 end;
40
41 procedure TAutoPtr<T>.Reset(aObj: T);
42 begin
43 if aObj <> fObj then
44 begin
45 FreeAndNil(fObj);
46 fObj := aObj;
47 end;
48 end;
49
50 destructor TAutoPtr<T>.Destroy;
51 begin
52 if fObj <> nil then
53 begin
54 FreeAndNil(fObj);
55 end;
56
57 inherited;
58 end;
59
60 function TAutoPtr<T>.Get: T;
61 begin
62 Result := fObj;
63 end;
1、在Release方法內的“fObj := nil”,編譯器將不支持,因為fObj為T類型,T可以為值類型,值類型賦值為nil是不允許的。
2、在Reset(aObj: T)方法內的“aObj <> fObj”,編譯器將不支持,雖然aObj和fObj都為T類型,但是泛型T為任意類型,並不是任何類型都支持“<>”比較運算符的。
3、Destroy方法內的“if fObj = nil then”不被支持,原因和第一點一樣。
4、Destroy方法內的“FreeAndNil(fObj)”不被支持,因為T可能是值類型,原因和第一點一樣。