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