smart pointers(智能指針)是行為很像指針但是增加了指針沒有提供的功能的 objects。例如,《C++箴言:使用對象管理資源》闡述了標准 auto_ptr 和 tr1::shared_ptr 是怎樣被應用於在恰當的時間自動刪除的 heap-based resources(基於堆的資源)的。STL containers 內的 iterators(迭代器)幾乎始終是 smart pointers(智能指針);你絕對不能指望用 "++" 將一個 built-in pointer(內建指針)從一個 linked list(線性鏈表)的一個節點移動到下一個,但是 list::iterators 可以做到。
real pointers(真正的指針)做得很好的一件事是支持 implicit conversions(隱式轉換)。derived class pointers(派生類指針)隱式轉換到 base class pointers(基類指針),pointers to non-const objects(指向非常量對象的指針)轉換到 pointers to const objects(指向常量對象的指針),等等。例如,考慮在一個 three-level hierarchy(三層繼承體系)中能發生的一些轉換: class Top { ... };
class Middle: public Top { ... };
class Bottom: public Middle { ... };
Top *pt1 = new Middle; // convert Middle* => Top*
Top *pt2 = new Bottom; // convert Bottom* => Top*
const Top *pct2 = pt1; // convert Top* => const Top*
在 user-defined smart pointer classes(用戶定義智能指針類)中模仿這些轉換是需要技巧的。我們要讓下面的代碼能夠編譯: template
class SmartPtr {
public: // smart pointers are typically
explicit SmartPtr(T *realPtr); // initialized by built-in pointers
...
};
SmartPtr
SmartPtr
SmartPtr
SmartPtr
SmartPtr
// SmartPtr
在同一個 template(模板)的不同 instantiations(實例化)之間沒有 inherent relationship(繼承關系),所以編譯器認為 SmartPtr
在上面的 smart pointer(智能指針)的示例代碼中,每一個語句創建一個新的 smart pointer object(智能指針對象),所以現在我們就集中於我們如何寫 smart pointer constructors(智能指針的構造函數),讓它以我們想要的方式運轉。一個關鍵的事實是我們無法寫出我們需要的全部 constructors(構造函數)。在上面的 hierarchy(繼承體系)中,我們能從一個 SmartPtr class BelowBottom: public Bottom { ... };
我們就需要支持從 SmartPtr
大體上,我們需要的 constructors(構造函數)的數量是無限的。因為一個 template(模板)能被實例化而產生無數個函數,所以好像我們不需要為 SmartPtr 提供一個 constructor function(構造函數函數),我們需要一個 constructor template(構造函數模板)。這樣的 templates(模板)是 member function templates(成員函數模板)(常常被恰如其分地稱為 member templates(成員模板))——生成一個 class 的 member functions(成員函數)的 templates(模板)的范例: template
class SmartPtr {
public:
template
SmartPtr(const SmartPtr & other); // for a "generalized
... // copy constructor"
};
這就是說對於每一種類型 T 和每一種類型 U,都能從一個 SmartPtr 創建出一個 SmartPtr
上面的 generalized copy constructor(泛型化拷貝構造函數)沒有被聲明為 explicit(顯式)的。這是故意為之的。built-in pointer types(內建指針類型)之間的類型轉換(例如,從派生類指針到基類指針)是隱式的和不需要 cast(強制轉型)的,所以讓 smart pointers(智能指針)模仿這一行為是合理的。在 templatized constructor(模板化構造函數)中省略 explicit 正好做到這一點。
作為聲明,SmartPtr 的 generalized copy constructor(泛型化拷貝構造函數)提供的東西比我們想要的還多。是的,我們需要能夠從一個 SmartPtr
假如 SmartPtr 跟隨 auto_ptr 和 tr1::shared_ptr 的腳步,提供一個返回被這個 smart pointer(智能指針)持有的 built-in pointer(內建指針)的拷貝的 get member function(get 成員函數)(參見《 C++箴言:在資源管理類中准備訪問裸資源 》),我們可以用 constructor template(構造函數模板)的實現將轉換限定在我們想要的范圍: template
class SmartPtr {
public:
template
SmartPtr(const SmartPtr & other) // initialize this held ptr
: heldPtr(other.get()) { ... } // with others held ptr
T* get() const { return heldPtr; }
...
private: // built-in pointer held
T *heldPtr; // by the SmartPtr
};
我們通過 member initialization list(成員初始化列表),用 SmartPtr 持有的類型為 U* 的指針初始化 SmartPtr
member function templates(成員函數模板)的用途並不限於 constructors(構造函數)。它們的另一個常見的任務是用於支持 assignment(賦值)。例如,TR1 的 shared_ptr(再次參見《 C++箴言:使用對象管理資源 》)支持從所有兼容的 built-in pointers(內建指針),tr1::shared_ptrs,auto_ptrs 和 tr1::weak_ptrs構造,以及從除 tr1::weak_ptrs 以外所有這些賦值。這裡是從 TR1 規范中摘錄出來的一段關於 tr1::shared_ptr 的內容,包括它在聲明 template parameters(模板參數)時使用 class 而不是 typename 的偏好。(就像《 C++箴言:理解typename的兩個含義 》中闡述的,在這裡的上下文環境中,它們的含義嚴格一致。) template
public:
template
explicit shared_ptr(Y * p); // any compatible
template
shared_ptr(shared_ptr
template
explicit shared_ptr(weak_ptr
template
explicit shared_ptr(auto_ptr
template
shared_ptr& operator=(shared_ptr
template
shared_ptr& operator=(auto_ptr
...
};
除了 generalized copy constructor(泛型化拷貝構造函數),所有這些 constructors(構造函數)都是 explicit(顯式)的。這就意味著從 shared_ptr 的一種類型到另一種的 implicit conversion(隱式轉換)是被允許的,但是從一個 built-in pointer(內建指針)或其 smart pointer type(智能指針類型)的 implicit conversion(隱式轉換)是不被許可的。(explicit conversion(顯式轉換)——例如,經由一個 cast(強制轉型)——還是可以的。)同樣引起注意的是 auto_ptrs 被傳送給 tr1::shared_ptr 的 constructors(構造函數)和 assignment operators(