c++共享指針分享_第1頁
c++共享指針分享_第2頁
c++共享指針分享_第3頁
c++共享指針分享_第4頁
c++共享指針分享_第5頁
已閱讀5頁,還剩26頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

1、共享指針分享1共享指針-簡介沿革: shared_ptr最初實(shí)現(xiàn)于Boost庫中,后來被C+標(biāo)準(zhǔn)委員會(huì)收錄于TR1技術(shù)報(bào)告中,成為C+0 x的一部分。特點(diǎn): shared_ptr是一種智能指針(smart pointer)。shared_ptr的作用有如同指針,但會(huì)記錄有多少個(gè)shared_ptrs共同指向一個(gè)對(duì)象。這便是所謂的引用計(jì)數(shù)(reference counting)。一旦最后一個(gè)這樣的指針被銷毀,也就是一旦某個(gè)對(duì)象的引用計(jì)數(shù)變?yōu)?,這個(gè)對(duì)象會(huì)被自動(dòng)刪除。這在非環(huán)形數(shù)據(jù)結(jié)構(gòu)中防止資源泄露很有幫助。典型的應(yīng)用1#include boost/shared_ptr.hpp#include #

2、include class A public: virtual void sing()=0;protected: virtual A() ;class B : public A public: virtual void sing() std:cout Do re mi fa so la; ;boost:shared_ptr createA() boost:shared_ptr p(new B(); return p;int main() typedef std:vectorboost:shared_ptr container_type; typedef container_type:itera

3、tor iterator; container_type container; for (int i=0;i10;+i) container.push_back(createA(); std:cout sing(); 創(chuàng)建的對(duì)象都保存在容器里面,從容器里面刪除的時(shí)候則對(duì)象的智能指針進(jìn)行內(nèi)存釋放典型的應(yīng)用2#include boost/shared_ptr.hpp#include class A boost:shared_ptr no_;public: A(boost:shared_ptr no) : no_(no) void value(int i) *no_=i; ;class B boos

4、t:shared_ptr no_;public: B(boost:shared_ptr no) : no_(no) int value() const return *no_; ;int main() boost:shared_ptr temp(new int(14); A a(temp); B b(temp); a.value(28); assert(b.value()=28);類A和B都保存了一個(gè)shared_ptr. 在創(chuàng)建A和B的實(shí)例時(shí),shared_ptr temp被傳送到它們的構(gòu)造函數(shù)。這意味著共有三個(gè)shared_ptr:a,b, 和temp,它們都引向同一個(gè)int實(shí)例。如果我們

5、用指針來實(shí)現(xiàn)對(duì)一個(gè)的共享,A和B必須能夠在某個(gè)時(shí)間指出這個(gè)int要被刪除。在這個(gè)例子中,直到main的結(jié)束,引用計(jì)數(shù)為3,當(dāng)所有shared_ptr離開了作用域,計(jì)數(shù)將達(dá)到0,而最后一個(gè)智能指針將負(fù)責(zé)刪除共享的int.Shared_ptr使用陷阱條款1:不要把一個(gè)原生指針給多個(gè)shared_ptr管理int* ptr = new int;shared_ptr p1(ptr);shared_ptr p2(ptr); /logic errorptr對(duì)象被刪除了2次Shared_ptr使用陷阱條款2:不要把this指針給shared_ptrclass Testpublic: void Do() m_

6、sp = shared_ptr(this); private: shared_ptr m_member_sp;Test* t = new Test;shared_ptr local_sp(t);p-Do();發(fā)生什么事呢,t對(duì)象被刪除了2次!t對(duì)象給了local_sp管理,然后在m_sp = shared_ptr(this)這句里又請了一尊神來管理t。Shared_ptr使用陷阱條款3:shared_ptr作為被保護(hù)的對(duì)象的成員時(shí),小心因循環(huán)引用造成無法釋放資源。假設(shè)a對(duì)象中含有一個(gè)shared_ptr指向b對(duì)象;假設(shè)b對(duì)象中含有一個(gè)shared_ptr指向a對(duì)象并且a,b對(duì)象都是堆中分配的。

7、很輕易就能與他們失去最后聯(lián)系。考慮某個(gè)shared_ptr local_a;是我們能最后一個(gè)看到a對(duì)象的共享智能指針,其use_count=2,因?yàn)閷?duì)象b中持有a的指針。所以當(dāng)local_a說再見時(shí),local_a只是把a(bǔ)對(duì)象的use_count改成1。同理b對(duì)象。然后我們再也看不到a,b的影子了,他們就靜靜的躺在堆里,成為斷線的風(fēng)箏。解決方案是:Use weak_ptr to break cycles.Shared_ptr 循環(huán)引用#include #include #include #include class parent;class children; typedef boost:sh

8、ared_ptr parent_ptr;typedef boost:shared_ptr children_ptr; class parentpublic: parent() std:cout destroying parentn; public: children_ptr children;class childrenpublic: children() std:cout children = son; son-parent = father; void main() std:coutbegin test.n; test(); std:coutend test.n;Shared_ptr使用陷

9、阱條款4:不要在函數(shù)實(shí)參里創(chuàng)建shared_ptrfunction ( shared_ptr(new int), g( ) ); /有缺陷可能的過程是先new int,然后調(diào)g( ),g( )發(fā)生異常,shared_ptr沒有創(chuàng)建,int內(nèi)存泄露shared_ptr p(new int();f(p, g(); /Boost推薦寫法Shared_ptr使用陷阱條款5:對(duì)象內(nèi)部生成shared_ptr前面說過,不能把this指針直接扔給shared_ptr. 但是沒有禁止在對(duì)象內(nèi)部生成自己的shared_ptrclass Y: public boost:enable_shared_from_thi

10、s boost:shared_ptr GetSelf() return shared_from_this(); ;Y y;boost:shared_ptr p= y.GetSelf(); /無知的代碼,y根本就不是new出來的Y* y = new Y;boost:shared_ptr p= y-GetSelf(); /似是而非,仍舊程序崩盤。Boost文檔說,在調(diào)用shared_from_this()之前,必須存在一個(gè)正常途徑創(chuàng)建的shared_ptrboost:shared_ptr spy(new Y)boost:shared_ptr p = spy-GetSelf(); /OKShared

11、_ptr使用陷阱條款6 :處理不是new的對(duì)象要小心。int* pi = (int*)malloc(4)shared_ptr sp( pi ) ; /delete馬嘴不對(duì)malloc驢頭。Shared_ptr使用陷阱條款7:多線程對(duì)引用計(jì)數(shù)的影響。/Boost文檔說read,write同時(shí)對(duì)shared_ptr操作時(shí),行為不確定。這是因?yàn)閟hared_ptr本身有兩個(gè)成員px,pi。多線程同時(shí)對(duì)px讀寫是要出問題的。與一個(gè)int的全局變量多線程讀寫會(huì)出問題的原因一樣。Shared_ptr使用陷阱條款9:學(xué)會(huì)用刪除器struct Test_Deleter void operator ()( Te

12、st* p) :free(p); ;Test* t = (Test*)malloc(sizeof(Test);new (t) Test;shared_ptr sp( t , Test_Deleter() ); /刪除器可以改變share_ptr銷毀對(duì)象行為templatestruct Array_Deleter void operator ()( T*) delete p; ;int* pint = new int100;shared_ptr p (pint, Array_Deleter() );有了刪除器,shared_array無用武之地了。class public: void opera

13、tor()(FILE* file) std:cout The has been called with a FILE*, which will now be closed.n; if () fclose(file); ;int main() std:cout shared_ptr example with a custom deallocator.n; FILE* f=fopen(test.txt,r); if (f=0) std:cout Unable to open filen; throw Unable to open file; boost:shared_ptr my_shared_f

14、ile(f, (); / 定位文件指針 fseek(my_shared_(),42,SEEK_SET); std:cout By now, the been closed!n;Shared_ptr使用陷阱條款10:學(xué)會(huì)用分配器shared_ptr p( (new Test), Test_Deleter(), Mallocator() );注意刪除器Test_Deleter是針對(duì)Test類的。分配器是針對(duì)shared_ptr內(nèi)部數(shù)據(jù)的。Mallocator()是個(gè)臨時(shí)對(duì)象(無狀態(tài)的),符合STL分配器規(guī)約。template class Mallocator /略。 T * allocate(co

15、nst size_t n) const return singleton_pool:malloc(); /略。存放引用計(jì)數(shù)的地方是堆內(nèi)存,需要16-20字節(jié)的開銷。如果大量使用shared_ptr會(huì)造成大量內(nèi)存碎片。shared_ptr構(gòu)造函數(shù)的第3個(gè)參數(shù)是分配器,可以解決這個(gè)問題。Shared_ptr使用陷阱條款11 weak_ptr在使用前需要檢查合法性。weak_ptr wp;shared_ptr sp(new K); /sp.use_count()=1wp = sp; /wp不會(huì)改變引用計(jì)數(shù),所以sp.use_count()=1shared_ptr sp_ok = wp.lock();

16、 /wp沒有重載-操作符。只能這樣取所指向的對(duì)象shared_ptr sp_null = wp.lock(); /sp_null .use_count()=0;因?yàn)樯鲜龃a中sp和sp_ok離開了作用域,其容納的K對(duì)象已經(jīng)被釋放了。得到了一個(gè)容納NULL指針的sp_null對(duì)象。在使用wp前需要調(diào)用wp.expired()函數(shù)判斷一下。因?yàn)閣p還仍舊存在,雖然引用計(jì)數(shù)等于0,仍有某處“全局”性的存儲(chǔ)塊保存著這個(gè)計(jì)數(shù)信息。直到最后一個(gè)weak_ptr對(duì)象被析構(gòu),這塊“堆”存儲(chǔ)塊才能被回收。否則weak_ptr無法直到知道所容納的那個(gè)指針資源的當(dāng)前狀態(tài)。Shared_ptr使用陷阱條款12 不要n

17、ew shared_ptr。本來shared_ptr就是為了管理指針資源的,不要又引入一個(gè)需要管理的指針資源shared_ptr*Shared_ptr使用陷阱條款13 盡量不要get。class B.;class D : public B .; /繼承層次關(guān)系shared_ptr sp (new D); /通過隱式轉(zhuǎn)換,儲(chǔ)存D的指針。B* b = sp.get(); /shared_ptr辛辛苦苦隱藏的原生指針就這么被刨出來了。D* d = dynamic_cast(b); /這是使用get的正當(dāng)理由嗎?正確的做法shared_ptr spb (new D) ;shared_ptr spd =

18、 shared_dynamic_cast(spb); /變成子類的指針shared_ptr在竭盡全力表演的像一個(gè)原生指針,原生指針能干的事,它也基本上能干。另一個(gè)同get相關(guān)的錯(cuò)誤shared_ptr sp(new T);shared_ptr sp2( sp.get() ) ;/指針會(huì)刪2次而錯(cuò)誤。Shared_ptr使用陷阱條款14 不要在構(gòu)造函數(shù)里調(diào)用shared_from_this。class Holder:public enable_shared_from_thispublic: Holder() shared_ptr sp = shared_from_this(); int x =

19、sp.use_count(); ;同前面條款5,不符合enable_shared_from_this使用前提??偨Y(jié)shared_ptr作為原生指針的替代品,能解決一定的內(nèi)存泄露問題。實(shí)際上初學(xué)原生指針時(shí),每個(gè)人都遇到過野指針,刪兩次,忘記刪除等問題。學(xué)習(xí)shared_ptr也會(huì)遇到。shared_ptr的確能改善上述問題,并不能完全解決問題。Shared_ptr 使用場景在以下情況時(shí)使用 shared_ptr :當(dāng)有多個(gè)使用者使用同一個(gè)對(duì)象,而沒有一個(gè)明顯的擁有者時(shí)當(dāng)要把指針存入標(biāo)準(zhǔn)庫容器時(shí)當(dāng)要傳送對(duì)象到庫或從庫獲取對(duì)象,而沒有明確的所有權(quán)時(shí)當(dāng)管理一些需要特殊清除方式的資源時(shí),通過定制刪除器的

20、幫助實(shí)時(shí)處理效率要求不高的情況下Shared_ptr 使用技巧技巧1:一個(gè)接口和一個(gè)實(shí)現(xiàn)的完美分離頭文件h-class Iface public: Iface(); void doit();private: class impl; shared_ptr m_pimpl;對(duì)應(yīng)的cpp-class Iface:impl: private noncopyablepublic: impl() cerr 構(gòu)造函數(shù)endl; impl() cerr 析構(gòu)函數(shù)endl; void doit() cerr do函數(shù)doit(); 客戶程序-Iface f;f.justdoit();Shared_ptr 使用技

21、巧技巧1:一個(gè)接口和一個(gè)實(shí)現(xiàn)的完美分離頭文件h-class Iface public: Iface(); void justdoit();private: class impl; shared_ptr m_pimpl;對(duì)應(yīng)的cpp-class Iface:impl: private noncopyablepublic: impl() cerr 構(gòu)造函數(shù)endl; impl() cerr 析構(gòu)函數(shù)endl; void doit() cerr do函數(shù)doit(); 客戶程序-Iface f;f.justdoit();接口頭文件把實(shí)現(xiàn)類隱藏的非常深。只暴露出實(shí)現(xiàn)類的名字是impl, 而且impl還

22、是私有的。shared_ptr解決了“刪除指向不完整類,沒有調(diào)用析構(gòu)函數(shù)”的問題,所以不會(huì)因此泄露內(nèi)存??蛻舫绦蛑猩踔量床坏絪hared_ptr的影子。Shared_ptr 使用技巧技巧2:一個(gè)接口和多個(gè)實(shí)現(xiàn)的完美分離頭文件h-class Iface 。 virtual void doit()=0 ;protected: Iface() /禁止直接刪除指針;shared_ptr create(int which);對(duì)應(yīng)的cpp-class impl_1: public Iface,private noncopyable 。 virtual void doit() cerrimpl_1:doen

23、dl; ;class impl_2: public Iface, private noncopyable 。 virtual void doit() cerrimpl_2:doendl; ;shared_ptr create(int which_one) if (which_one=1) return shared_ptr(new impl_1); else return shared_ptr(new impl_2);客戶程序-shared_ptr f = create(1);f-doit();通過create參數(shù)需要告訴系統(tǒng),想調(diào)用哪一個(gè)實(shí)現(xiàn)Shared_ptr 使用技巧技巧3:庫開發(fā)者的指

24、針保護(hù)神。庫程序接口-X* CreateX(); /從庫中得到對(duì)象void DestroyX(X*); /將對(duì)象歸還給庫客戶程序-X* x = CreateX();delete x; /應(yīng)調(diào)DestroyX,武斷的delete。誰知道庫中的x對(duì)象不是malloc或靜態(tài)區(qū)出來的? /程序崩潰,憤怒的客戶: 和無辜的庫開發(fā)者 :(改進(jìn)一下,禁止new和delete庫程序接口-class Kpublic: int x;private: K(); /對(duì)象的創(chuàng)建和銷毀被私有化了,他們不再是公共事業(yè)了。 K(); private: friend class K_Creater; friend class

25、K_Deleter; ;struct K_Deleter void operator()(K* p) delete p; ;struct K_Creater static shared_ptr Create() return shared_ptr(new K, K_Deleter() ); ;客戶程序-/K* p = new K; 被禁止了shared_ptr p = K_Creator:Create();/delete p.get(); 被禁止了/shared_ptr sp(p.get(); 也被禁止了!K* p = p.get(); /未被禁止。free(p) ; /程序崩潰,無法解決這個(gè)

26、問題。庫開發(fā)者往往頭痛于自己的指針孩子們不能被客戶善待。Shared_ptr 使用技巧技巧4:封裝句柄類。HANDLE :CreateProcess();void :CloseHandle(HANDLE);typedef shared_ptr auto_handle;auto_handle createProcess() auto_handle pv( :CreateProcess(), :CloseHandle ); return pv;把操作系統(tǒng)的“句柄”當(dāng)成“原生指針”管理。技巧5:空刪除器Shared_ptr 使用技巧技巧5:空刪除器。在shared_ptr引用計(jì)數(shù)歸0時(shí),不刪除所持有

27、的對(duì)象指針class null_deleterpublic: void operator(K* t)void f(K* p) shared_ptr sp( p , null_deleter() );sp不刪除p指針。原因很多:1. 不應(yīng)刪除p: p的生存期已經(jīng)被其他程序管理的很好了,2. 不能刪除p: p的來頭很大,可能是一塊靜態(tài)存儲(chǔ)區(qū)3. 空刪除器的shared_ptr可以持有this指針!Shared_ptr 使用技巧技巧6:萬能的void*被更強(qiáng)大的Shared_ptr取代。struct X X() cerrX() Calledendl; ;struct Y Y() cerrY() Calledendl; ;struct Z Z() cerrZ() Calledend

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論