shared_ptr
Header: "boost/shared_ptr.hpp"
幾乎全部有效程序都需要一些引用記數(reference-counted)形式的智能指針.這些只能指針使我們不再需要自己寫復雜的邏輯來控制被共享對象的生命期.當引用記數降到0,沒有對象對這個被共享對象感興趣,所以它自動delete.引用記數智能指針被分類為侵入式和非侵入式.類格式提供一個確定的功能函數或者數據成員來管理引用記數.那意味著設計類帶有預見性的可以與侵入式,引用記數智能指針類,或者改進型共同工作.非侵入式,引用記數智能指針不需要管理任何類型.引用記數智能指針假設內存的所有權與存儲他們的指針相關聯.在沒有智能指針幫助下使用共享對象的問題是必須有人最終delete共享內存.誰做,何時做?沒有引用記數智能指針,一個外部的生命期管理必須強加于被管理的內存,它典型的表達了所有權集合之間存在很強的互相依附關系.那樣妨礙了可重用性和增加了復雜度.
被管理的類或許有一個屬性使它能成為一個優秀的候選來和引用記數智能指針一起使用.比如,事實上,它復制開銷很大,或者它表示需要被多個實例共享,合理的共享所有權.還有的情況不存在一個明確的共享資源擁有者.應用引用記數智能指針使需要在對象間分享一個共享資源成為可能.同樣在標準庫中使沒有危險和沒有泄露的條件下存儲對象指針成為可能,尤其面對異常時或者當從容器中移除元素時.當你在容器中存儲指針時,你能得到多態的優勢,效率改良(如果復制需要很大花費的話),還具備存儲多個相同對象的能力,關聯容器的專門檢查.
在你有理由并決定使用引用記數智能指針后,怎樣選擇使用侵入式還是非侵入式的設計?非侵入式
幾乎總是較好的選擇因為它的一般適用性,對現存代碼影響少,靈活.你可以使用非侵入式,引用記數智能指針對那些你希望保持不變的類.通常的方法是改編一個類來和侵入式的一起工作,引用記數智能指針是從引用記數基類派生出來的.乍一看它的變化或許伴隨著更多的開銷.但是至少,它增加了相互依存關系和加強了可重用性.它同樣增加了對象大小,或在一些范圍內限制了可用性.
一個shared_ptr可以由原生指針,另一個shared_ptr,一個std::auto_ptr,或者一個boost::weak_ptr創建.它同樣可以傳遞第二個實參到shared_ptr的constructor,當做釋放者.
它會被最后調用來釋放被共享資源.這是非常有用的對于管理那些不是通過new分配和delete銷毀的資源(我們稍后將看到一些創建用戶釋放者的例子).shared_ptr被創建后,它會被像普通指針一樣的使用,沒有被明確刪除的情況下回顯示異常.
這是shared_ptr的一個部分綱要;最重要的成員和自由函數被列出來,隨后將簡短的討論.
namespace boost {
template<typename T> class shared_ptr {
public:
template <class Y> explicit shared_ptr(Y* p);
template <class Y,class D> shared_ptr(Y* p,D d);
~shared_ptr();
shared_ptr(const shared_ptr & r);
template <class Y> explicit
shared_ptr(const weak_ptr<Y>& r);
template <class Y> explicit shared_ptr(std::auto_ptr<Y>& r);
shared_ptr& operator=(const shared_ptr& r);
void reset();
T& operator*() const;
T* operator->() const;
T* get() const;
bool unique() const;
long use_count() const;
operator unspecified-bool-type() const;
void swap(shared_ptr<T>& b);
};
template <class T,class U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
}
Members
template <class Y> explicit shared_ptr(Y* p);
這個constructor接管參數指針p的所有權.失參p必須是一個有效的Y的指針.創建后引用記數被設為1.僅當constructor為std::bad_alloc時拋出異常(它僅在引用記數沒分配真種不太可能的情況下發生).
template <class Y,class D> shared_ptr(Y* p,D d);
此constructor有倆個參數.第一個是shared_ptr接管所有權的資源,第二個是負責釋放資源的對象當shared_ptr被銷毀.被存儲的資源被傳遞給對象以d(p).p的有效值取決于d.如果reference counter不能被分配,shared_ptr拋出std::bad_alloc類型的異常.
shared_ptr(const shared_ptr& r);
在r中被存儲資源通過創建shared_ptr對象被分享,reference count加1.這個copy constructor不拋出異常.
template <class Y> explicit shared_ptr(const weak_ptr<Y>& r);
從weak_ptr(在本章后面介紹)創建一個shared_ptr.它使weak_ptr具有thread-safe的用處,因為被共享資源的reference count將通過weak_ptr的參數自增(weak_ptr不會影響被共享資源的reference count).如果weak_ptr是空的話(r.use_count()==0),shared_ptr拋出bad_weak_ptr類型的異常.
template <typename Y> shared_ptr(std::auto_ptr<Y>& r);
這個construction從auto_ptr接過r存儲對象的所有權通過存儲一個指針副本并釋放原auto_ptr.創建后reference count是1.代表r,當然,耗盡內存的情況下,reference counter無法分配將拋出std::bad_alloc
~shared_ptr();
shared_ptr的destructor減少reference count 1.如果count為0,被指資源delete.delete指針將通過調用operator delete或者使用用戶提供的釋放者對象來銷毀,此對象將被存儲的指針作為它的唯一參數調用.destructor不拋出異常.
shared_ptr& operator=(const shared_ptr& r);
copy assignment operator共享r中的資源并停止共享當前被共享的資源.此copy assignment operator不拋出異常
void reset();
此函數被用于停止共享被存儲指針的所有權.被共享資源的reference count變0.
T& operator*() const;
此operator返回一個被存儲指針所指向對象的引用,如果指針為null,operator*導致未定義行為.此operator不拋出異常
T* operator->() const;
此operator返回被存儲的指針.同operator*一起使smart pointer看起來想普通指針.此operator不拋出異常
T* get() const;
get function是檢查被存儲指針是否為null的首選方法(在null情形下operator* and operator->導致為定義行為).注意它同樣可以測試一個shared_ptr是否包含一個有效指針通過使用暗式Boolean類型轉換.此function不拋出異常.
bool unique() const;
此函數返回true當shared_ptr是被存儲指針的唯一擁有者;否則,返回false.unique不拋出異常.
long use_count() const;
此函數返回指針的reference count.在調試用途中尤其有用,因為他能被用來獲得reference count的簡短信息在執行程序的關鍵點處.保守的使用它.為了使一些shared_ptr的接口可以執行,計算reference count也許有很大開銷甚至是不可能的.此函數不拋出異常.
operator unspecified-bool-type() const;
它暗式轉換為一個類型,unspecified-bool-type,使用Boolean來測試一個smart pointer成為可能.如果當前存儲一個有效指針則為true,否則,則為false.此轉換函數返回的類型是為規定的.使用bool作為返回類型將允許一些無意義的操作,代表性的,使用safe bool idiom來實現,的確是一個漂亮的辦法來確保僅當適當的邏輯測試才能被使用.此函數不拋出異常.
void swap(shared_ptr<T>& b);
它有時方便的交換倆個shared_ptrs的內容.swap函數交換被存儲的指針(和它們的reference counts).此函數不拋出異常.
Free Functions
template <typename T,typename U>
shared_ptr<T> static_pointer_cast(const shared_ptr<U>& r);
執行一個static_cast從被存儲的指針到shared_ptr,我們可以檢查指針然后轉換它,但是我們不能存儲它在另外一個shared_ptr中;新的shared_ptr將認為它是指針關聯的資源的第一個管理者.它可以被補救通過static_pointer_cast.使用這個函數確保指針剩余的reference count不變性.static_pointer_cast不拋出異常.
Usage
shared_ptr解決的主要問題是在正確是時間delete被多個用戶共享的資源.這里有個直觀的例子,
有倆個classes, A和B,共享一個int實例.使用boost::shared_ptr,你需要包含"boost/shared_ptr.hpp".
#include "boost/shared_ptr.hpp"
#include <cassert>
class A {
boost::shared_ptr<int> no_;
public:
A(boost::shared_ptr<int> no) : no_(no) {}
void value(int i) {
*no_=i;
}
};
class B {
boost::shared_ptr<int> no_;
public:
B(boost::shared_ptr<int> no) : no_(no) {}
int value() const {
return *no_;
}
};
int main() {
boost::shared_ptr<int> temp(new int(14));
A a(temp);
B b(temp);
a.value(28);
assert(b.value()==28);
}
classes A和B都存儲一個shared_ptr<int>.當創造A和B的實例時,shared_ptr temp被傳遞進了他們的constructor.這以為著這三個shared_ptr,a,b,和temp現在引用一個共同的int實例.我們用指針達到了分享一個int的目的,A和B將計算出它應該在何時被delete.在本例中,reference count是3直到main的結束,所有的shared_ptr跳出作用域,減少count知道為0,允許最后一個smart pointers來delete共享的int.