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