c++共享指针分享_第1页
c++共享指针分享_第2页
c++共享指针分享_第3页
c++共享指针分享_第4页
c++共享指针分享_第5页
已阅读5页,还剩26页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、共享指针分享1共享指针-简介沿革: shared_ptr最初实现于Boost库中,后来被C+标准委员会收录于TR1技术报告中,成为C+0 x的一部分。特点: shared_ptr是一种智能指针(smart pointer)。shared_ptr的作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。典型的应用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(); 创建的对象都保存在容器里面,从容器里面删除的时候则对象的智能指针进行内存释放典型的应用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都保存了一个shared_ptr. 在创建A和B的实例时,shared_ptr temp被传送到它们的构造函数。这意味着共有三个shared_ptr:a,b, 和temp,它们都引向同一个int实例。如果我们

5、用指针来实现对一个的共享,A和B必须能够在某个时间指出这个int要被删除。在这个例子中,直到main的结束,引用计数为3,当所有shared_ptr离开了作用域,计数将达到0,而最后一个智能指针将负责删除共享的int.Shared_ptr使用陷阱条款1:不要把一个原生指针给多个shared_ptr管理int* ptr = new int;shared_ptr p1(ptr);shared_ptr p2(ptr); /logic errorptr对象被删除了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();发生什么事呢,t对象被删除了2次!t对象给了local_sp管理,然后在m_sp = shared_ptr(this)这句里又请了一尊神来管理t。Shared_ptr使用陷阱条款3:shared_ptr作为被保护的对象的成员时,小心因循环引用造成无法释放资源。假设a对象中含有一个shared_ptr指向b对象;假设b对象中含有一个shared_ptr指向a对象并且a,b对象都是堆中分配的。

7、很轻易就能与他们失去最后联系。考虑某个shared_ptr local_a;是我们能最后一个看到a对象的共享智能指针,其use_count=2,因为对象b中持有a的指针。所以当local_a说再见时,local_a只是把a对象的use_count改成1。同理b对象。然后我们再也看不到a,b的影子了,他们就静静的躺在堆里,成为断线的风筝。解决方案是:Use weak_ptr to break cycles.Shared_ptr 循环引用#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:不要在函数实参里创建shared_ptrfunction ( shared_ptr(new int), g( ) ); /有缺陷可能的过程是先new int,然后调g( ),g( )发生异常,shared_ptr没有创建,int内存泄露shared_ptr p(new int();f(p, g(); /Boost推荐写法Shared_ptr使用陷阱条款5:对象内部生成shared_ptr前面说过,不能把this指针直接扔给shared_ptr. 但是没有禁止在对象内部生成自己的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文档说,在调用shared_from_this()之前,必须存在一个正常途径创建的shared_ptrboost:shared_ptr spy(new Y)boost:shared_ptr p = spy-GetSelf(); /OKShared

11、_ptr使用陷阱条款6 :处理不是new的对象要小心。int* pi = (int*)malloc(4)shared_ptr sp( pi ) ; /delete马嘴不对malloc驴头。Shared_ptr使用陷阱条款7:多线程对引用计数的影响。/Boost文档说read,write同时对shared_ptr操作时,行为不确定。这是因为shared_ptr本身有两个成员px,pi。多线程同时对px读写是要出问题的。与一个int的全局变量多线程读写会出问题的原因一样。Shared_ptr使用陷阱条款9:学会用删除器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销毁对象行为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:学会用分配器shared_ptr p( (new Test), Test_Deleter(), Mallocator() );注意删除器Test_Deleter是针对Test类的。分配器是针对shared_ptr内部数据的。Mallocator()是个临时对象(无状态的),符合STL分配器规约。template class Mallocator /略。 T * allocate(co

15、nst size_t n) const return singleton_pool:malloc(); /略。存放引用计数的地方是堆内存,需要16-20字节的开销。如果大量使用shared_ptr会造成大量内存碎片。shared_ptr构造函数的第3个参数是分配器,可以解决这个问题。Shared_ptr使用陷阱条款11 weak_ptr在使用前需要检查合法性。weak_ptr wp;shared_ptr sp(new K); /sp.use_count()=1wp = sp; /wp不会改变引用计数,所以sp.use_count()=1shared_ptr sp_ok = wp.lock();

16、 /wp没有重载-操作符。只能这样取所指向的对象shared_ptr sp_null = wp.lock(); /sp_null .use_count()=0;因为上述代码中sp和sp_ok离开了作用域,其容纳的K对象已经被释放了。得到了一个容纳NULL指针的sp_null对象。在使用wp前需要调用wp.expired()函数判断一下。因为wp还仍旧存在,虽然引用计数等于0,仍有某处“全局”性的存储块保存着这个计数信息。直到最后一个weak_ptr对象被析构,这块“堆”存储块才能被回收。否则weak_ptr无法直到知道所容纳的那个指针资源的当前状态。Shared_ptr使用陷阱条款12 不要n

17、ew shared_ptr。本来shared_ptr就是为了管理指针资源的,不要又引入一个需要管理的指针资源shared_ptr*Shared_ptr使用陷阱条款13 尽量不要get。class B.;class D : public B .; /继承层次关系shared_ptr sp (new D); /通过隐式转换,储存D的指针。B* b = sp.get(); /shared_ptr辛辛苦苦隐藏的原生指针就这么被刨出来了。D* d = dynamic_cast(b); /这是使用get的正当理由吗?正确的做法shared_ptr spb (new D) ;shared_ptr spd =

18、 shared_dynamic_cast(spb); /变成子类的指针shared_ptr在竭尽全力表演的像一个原生指针,原生指针能干的事,它也基本上能干。另一个同get相关的错误shared_ptr sp(new T);shared_ptr sp2( sp.get() ) ;/指针会删2次而错误。Shared_ptr使用陷阱条款14 不要在构造函数里调用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使用前提。总结shared_ptr作为原生指针的替代品,能解决一定的内存泄露问题。实际上初学原生指针时,每个人都遇到过野指针,删两次,忘记删除等问题。学习shared_ptr也会遇到。shared_ptr的确能改善上述问题,并不能完全解决问题。Shared_ptr 使用场景在以下情况时使用 shared_ptr :当有多个使用者使用同一个对象,而没有一个明显的拥有者时当要把指针存入标准库容器时当要传送对象到库或从库获取对象,而没有明确的所有权时当管理一些需要特殊清除方式的资源时,通过定制删除器的

20、帮助实时处理效率要求不高的情况下Shared_ptr 使用技巧技巧1:一个接口和一个实现的完美分离头文件h-class Iface public: Iface(); void doit();private: class impl; shared_ptr m_pimpl;对应的cpp-class Iface:impl: private noncopyablepublic: impl() cerr 构造函数endl; impl() cerr 析构函数endl; void doit() cerr do函数doit(); 客户程序-Iface f;f.justdoit();Shared_ptr 使用技

21、巧技巧1:一个接口和一个实现的完美分离头文件h-class Iface public: Iface(); void justdoit();private: class impl; shared_ptr m_pimpl;对应的cpp-class Iface:impl: private noncopyablepublic: impl() cerr 构造函数endl; impl() cerr 析构函数endl; void doit() cerr do函数doit(); 客户程序-Iface f;f.justdoit();接口头文件把实现类隐藏的非常深。只暴露出实现类的名字是impl, 而且impl还

22、是私有的。shared_ptr解决了“删除指向不完整类,没有调用析构函数”的问题,所以不会因此泄露内存。客户程序中甚至看不到shared_ptr的影子。Shared_ptr 使用技巧技巧2:一个接口和多个实现的完美分离头文件h-class Iface 。 virtual void doit()=0 ;protected: Iface() /禁止直接删除指针;shared_ptr create(int which);对应的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参数需要告诉系统,想调用哪一个实现Shared_ptr 使用技巧技巧3:库开发者的指

24、针保护神。库程序接口-X* CreateX(); /从库中得到对象void DestroyX(X*); /将对象归还给库客户程序-X* x = CreateX();delete x; /应调DestroyX,武断的delete。谁知道库中的x对象不是malloc或静态区出来的? /程序崩溃,愤怒的客户: 和无辜的库开发者 :(改进一下,禁止new和delete库程序接口-class Kpublic: int x;private: K(); /对象的创建和销毁被私有化了,他们不再是公共事业了。 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) ; /程序崩溃,无法解决这个

26、问题。库开发者往往头痛于自己的指针孩子们不能被客户善待。Shared_ptr 使用技巧技巧4:封装句柄类。HANDLE :CreateProcess();void :CloseHandle(HANDLE);typedef shared_ptr auto_handle;auto_handle createProcess() auto_handle pv( :CreateProcess(), :CloseHandle ); return pv;把操作系统的“句柄”当成“原生指针”管理。技巧5:空删除器Shared_ptr 使用技巧技巧5:空删除器。在shared_ptr引用计数归0时,不删除所持有

27、的对象指针class null_deleterpublic: void operator(K* t)void f(K* p) shared_ptr sp( p , null_deleter() );sp不删除p指针。原因很多:1. 不应删除p: p的生存期已经被其他程序管理的很好了,2. 不能删除p: p的来头很大,可能是一块静态存储区3. 空删除器的shared_ptr可以持有this指针!Shared_ptr 使用技巧技巧6:万能的void*被更强大的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. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论