c深度探索系列智能指针smartpointer.docx
- 文档编号:6850240
- 上传时间:2023-01-11
- 格式:DOCX
- 页数:6
- 大小:25.64KB
c深度探索系列智能指针smartpointer.docx
《c深度探索系列智能指针smartpointer.docx》由会员分享,可在线阅读,更多相关《c深度探索系列智能指针smartpointer.docx(6页珍藏版)》请在冰豆网上搜索。
c深度探索系列智能指针smartpointer
c++深度探索系列智能指针(smartpointer)
主题索引:
一、剖析C++标准库智能指针(std:
:
auto_ptr)1.DoyouSmartPointer?
2.std:
:
auto_ptr的设计原理3.std:
:
auto_ptr高级使用指南4.你是否觉得std:
:
auto_ptr还不够完美?
二、C++条件,寻找构造更强大的智能指针(SmartPointer)的策略1.支持引用记数的多种设计策略2.支持处理多种资源3.支持Subclassing4.支持多线程条件下,线程安全的多种设计策略5.其它多种特殊要求下,再构造三、GenericProgramming基础技术和SmartPointer1.回首处理资源中的Traits技术2.回首多线程支持的设计四、COM实现中,SmartPointer设计原理五、著名C++库(标准和非标准)中的SmartPointer现状---------------------------------------------------------------------一、剖析C++标准库智能指针(std:
:
auto_ptr)1.DoyouSmartPointer?
SmartPointer,中文名:
智能指针,舶来品?
不可否认,资源泄露(resourceleak)曾经是C++程序的一大噩梦.垃圾回收机制(GarbageCollection)一时颇受注目.然而垃圾自动回收机制并不能满足内存管理的即时性和可视性,往往使高傲的程序设计者感到不自在.况且,C++实现没有引入这种机制.在探索中,C++程序员创造了锋利的"SmartPointer".一定程度上,解决了资源泄露问题.也许,经常的,你会写这样的代码:
//x拟为class:
//classx{//public:
//intm_Idata;//public:
//x(intm_PARAMin):
m_Idata(m_PARAMin){}//voidprint(){cout<//.....//}//voidfook(){x*m_PTRx=newA(m_PARAMin);m_PTRx->DoSomething();//#2deletem_PTRx;}是的,这里可能没什么问题.可在复杂、N行、m_PTRclassobj所指对象生命周期要求较长的情况下,你能保证你不会忘记deletem_PTRclassobj吗?
生活中,我们往往不应该有太多的口头保证,我们需要做些真正有用的东西.还有一个更敏感的问题:
异常.假如在#2方法执行期异常发生,函数执行终止,那么new出的对象就会泄露.于是,你可能会说:
那么就捕获异常来保证安全性好了.你写这样的程式:
voidfook(){A*m_PTRx=newA(m_PARAMin);try{m_PTRx->DoSomething();}catch(..){deletem_PTRx;throw;}deletem_PTRx;}哦!
天哪!
想象一下,你的系统,是否会象专为捕获异常而设计的.一天,有人给你建议:
"用SmartPointer,那很安全.".你可以这样重写你的程序:
voidfook(){auto_ptrm_SMPTRx(newx(m_PARAMin));m_SMPTRx->DoSomething();}OK!
你不太相信.不用delete吗?
是的.不用整天提心吊胆的问自己:
"我全部delete了吗?
",而且比你的delete策略更安全.然后,还有人告诉你,可以这样用呢:
ok1.auto_ptrm_SMPTR1(newx(m_PARAMin));auto_ptrm_SMPTR2(m_SMPTR1);//#2Maybeyoucancode#2likethis:
auto_ptrm_SMPTR2;m_SMPTR2=m_SMPTR1;ok2.auto_ptrm_SMPTR1(newint(32));ok3.auto_ptrm_SMPTR1;m_SMPTR1=auto_ptr(newint(100));也可以:
auto_ptrm_SMPTR1(auto_ptr(newint(100)));ok4.auto_ptrm_SMPTR1(newx(m_PARAMin));m_SMPTR1.reset(newx(m_PARAMin1));ok5.auto_ptrm_SMPTR1(newx(m_PARAMin));auto_ptrm_SMPTR2(m_SMPTR.release());cout<<(*m_SMPTR2).m_Idata<ok6.auto_ptrfook(){returnauto(newint(100));}ok7.............andsoon但不可这样用:
no1.char*chrarray=newchar[100];strcpy(chrarray,"Iamprogramming.");auto_ptrm_SMPTRchrptr(chrarray);//auto_ptr并不可帮你管理数组资源no2.vector>m_VECsmptr;m_VECsmptr.push_back(auto_ptr(newint(100)));//auto_ptr并不适合STL内容.no3.constauto_ptrm_SMPTR1(newx(100));auto_ptrm_SMPTR(newx(200));no4.xm_OBJx(300);auto_ptrm_SMPTR(&m_OBJx);no5x*m_PTR=newx(100);auto_ptrm_SMPTR=m_pTR;no6..........andsoon预先提及所有权的问题,以便下面带着疑问剖析代码?
power1.auto_ptrm_SMPTR1(newx(100));auto_ptrm_SMPTR2=m_SMPTR1;m_SMPTR2->print();//输出:
100.m_SMPTR1->print();//!
!
非法的.power2.auto_ptrm_SMPTR(newx(100));auto_ptrreturnfun(auto_ptrm_SMPTRin){returnm_SMPTRin;}auto_ptr=returnfun(m_SMPTR);//#5//在上面的#5中,我要告诉你对象所有权转移了两次.//什么叫对象所有权呢?
2.std:
:
auto_ptr的设计原理上面的一片正确用法,它们在干些什么?
一片非法,它们犯了什么罪?
一片什么所有权转移,它的内部机智是什么?
哦!
一头雾水?
下面我们就来剖析其实现机制.基础知识:
a.智能指针的关键技术:
在于构造栈上对象的生命期控制堆上构造的对象的生命期.因为在智能指针的内部,存储着堆对象的指针,而且在构析函数中调用delete行为.大致机构如下:
x*m_PTRx=newx(100);//#1templateauto_ptr{private:
T*m_PTR;//维护指向堆对象的指针,在auto_ptr定位后....//它应该指向#1构造的对象,即拥有所有权.~auto(){deletem_PTR;}....}b.所有权转移之说上面曾有一非法的程式片段如下:
auto_ptrm_SMPTR1(newx(100));auto_ptrm_SMPTR2=m_SMPTR1;m_SMPTR2->print();//输出:
100.m_SMPTR1->print();//!
!
非法的.按常理来说,m_SMPTR->print();怎么是非法的呢?
那是因为本来,m_SMPTR1维护指向newx(100)的指针,可是m_SMPTR2=m_SMPTR1;auto_ptr内部机制使得m_SMPTR1将对象的地址传给m_SMPTR2,而将自己的对象指针置为0.那么自然m_SMPTR->print();失败.这里程序设计者要负明显的职责的.那么auto_ptr为什么采取这样的策略:
保证所有权的单一性.亦保证了系统安全性.如果多个有全权的auto_ptr维护一个对象,那么在你消除一个auto_ptr时,将导致多个auto_ptr的潜在危险.下面我们以SGI-STL的auto_ptr设计为样本(去掉了无关分析的宏),来剖析其原理.#1templateclassauto_ptr{#2private:
#3_Tp*_M_ptr;//定义将维护堆对象的指针#4public:
#5typedef_Tpelement_type;//相关类型定义#6explicitauto_ptr(_Tp*__p=0)__STL_NOTHROW:
_M_ptr(__p){}#7auto_ptr(auto_ptr&__a)__STL_NOTHROW:
_M_ptr(__a.release()){}#8templateauto_ptr(auto_ptr<_Tp1>&__a)__STL_NOTHROW:
_M_ptr(__a.release()){}//#6、#7、#8是auto_ptr构造函数的三个版本.//#6注释:
传入对象的指针,构造auto_ptr.explicit关键字:
禁止隐式转换.//这就是ok2正确,而no5(隐式转换)错误的原因.//#7注释:
拷贝构造函数.//传入auto_ptr实例,构造auto_ptr.ok1、ok3使用了这个构造式.//它是一个很关键的构造函数,在具体情况下,我们再分析//#8注释:
auto_ptr的模板成员,可在继承对象重载的基础上,实现特殊功能.////举例:
//classA{public:
//virtualvoidfook(){cout<<"Iamprogramming"<///*..........*/};//classB:
publicA{//virtualvoidfook(){cout<<"Iamworking"<///*...........*/};//auto_ptrm_SMPTRa(newA(33));//实质:
//auto_ptrm_SMPTRb(m_SMPTRa);//基类的指针可以赋给派生类的指针////auto_ptrm_SMPTRb(newB(44));//实质:
//auto_ptrm_SMPTRa(m_SMPTRb);//派生类的指针不可赋给基类的指针////auto_ptrm_SMPTRa(newB(33));//ok!
//m_SMPTRa->fook()将调用派生类B的fook()//m_SMPTRa->A:
:
fook()将调用基类A的fook()////auto_ptrm_SMPTRb(newA(33));//wrong!
////#9auto_ptr&operator=(auto_ptr&__a)__STL_NOTHROW{#10if(&__a!
=this){delete_M_ptr;_M_ptr=__a.release();}#11return*this;#12}#13template#14auto_ptr&operator=(auto_ptr<_Tp1>&__a)__STL_NOTHROW{#15if(__a.get()!
=this->get()){delete_M_ptr;_M_ptr=__a.release();}#16return*this;#16}////#9~~#16两个版本的指派函数.//delete_M_ptr;在指派前,销毁原维护的对象.//_a.release();release操作,详细代码参见#20~~#23.//用于*this获得被指派对象,//且将原维护auto_ptr置空.//no3使用了第一种指派.//而权限转移正是_a.release()的结果.#17~auto_ptr()__STL_NOTHROW{delete_M_ptr;}//构析函数.消除对象.注意这里对对象的要求!
#17_Tp&operator*()const__STL_NOTHROW{return*_M_ptr;}#18_Tp*operator->()const__STL_NOTHROW{return_M_ptr;}#19_Tp*get()const__STL_NOTHROW{return_M_ptr;}////操作符重载.//#17注释:
提领操作(dereference),获得对象.见ok5用法.//#18注释:
成员运算符重载,返回对象指针.//#19注释:
普通成员函数.作用同于重载->运算符//#20_Tp*release()__STL_NOTHROW{#21_Tp*__tmp=_M_ptr;#22_M_ptr=0;#23return__tmp;}//上面已经详解#24voidreset(_Tp*__p=0)__STL_NOTHROW{#25delete_M_ptr;#26_M_ptr=__p;}////传入对象指针,改变auto_ptr维护的对象//且迫使auto_ptr消除原来维护的对象//见ok3用法.//AccordingtotheC++standard,theseconversionsarerequired.Most//present-daycompilers,however,donotenforcethatrequirement---and,//infact,mostpresent-daycompilersdonotsupportthelanguage//featuresthattheseconversionsrelyon.//下面这片段用于类型转化,目前没有任何编译器支持//具体技术细节不诉.#ifdef__SGI_STL_USE_AUTO_PTR_CONVERSIONS#27private:
#28template#29structauto_ptr_ref{_Tp1*_M_ptr;auto_ptr_ref(_Tp1*__p):
_M_ptr(__p){}};#30public:
#31auto_ptr(auto_ptr_ref<_Tp>__ref)__STL_NOTHROW:
_M_ptr(__ref._M_ptr){}#32template#33operatorauto_ptr_ref<_Tp1>()__STL_NOTHROW#34{returnauto_ptr_ref<_Tp>(this->release());}#35templateoperatorauto_ptr<_Tp1>()__STL_NOTHROW#36{returnauto_ptr<_Tp1>(this->release());}#37#endif/*__SGI_STL_USE_AUTO_PTR_CONVERSIONS*/#38};OK!
就是这样了.正如上面原理介绍处叙说,你需要正视两大特性:
1.构造栈对象的生命期控制堆上构造的对象的生命期2.通过release来保证auto_ptr对对象的独权.在我们对源码分析的基础上,重点看看:
no系列错误在何处?
no1.我们看到构析函数template~auto_ptr()_STL_NOTHROW{delete_M_ptr;}所以它不能维护数组,维护数组需要操作:
delete[]_M_ptr;no2.先提部分vector和auto_ptr代码:
a.提auto_ptr代码auto_ptr(auto_ptr&__a)__STL_NOTHROW:
_M_ptr(__a.release()){}b.提vector代码Part1:
voidpush_back(const_Tp&__x){if(_M_finish!
=_M_end_of_storage){construct(_M_finish,__x);++_M_finish;}else_M_insert_aux(end(),__x);}Part2:
templateinlinevoidconstruct(_T1*__p,//++++++++++++++++++++++++++++++++//const_T2&__value){+//++++++++++++++++++++++++++++++++//new(__p)_T1(__value);+//++++++++++++++++++++++++++++++++}Part3.templatevoidvector<_Tp,_Alloc>:
:
_M_insert_aux(iterator__position,//++++++++++++++++++++++++++++++++//const_Tp&__x)++//++++++++++++++++++++++++++++++++{if(_M_finish!
=_M_end_of_storage){construct(_M_finish,*(_M_finish-1));++_M_finish;//++++++++++++++++++++++++++++++++//_Tp__x_copy=__x;+//++++++++++++++++++++++++++++++++copy_backward(__position,_M_finish-2,_M_finish-1);*__position=__x_copy;}else{constsize_type__old_size=size();constsize_type__len=__old_size!
=0?
2*__old_size:
1;iterator__new_start=_M_allocate(__len);iterator__new_finish=__new_start;__STL_TRY{__new_finish=uninitialized_copy(_M_start,__position,__new_start);construct(__new_finish,__x);++__new_finish;__new_finish=uninitialized_copy(__position,_M_finish,__new_finish);}__STL_UNWIND((destroy(__new_start,__new_finish),_M_deallocate(__new_start,__len)));destroy(begin(),end());_M_deallocate(_M_start,_M_end_of_storage-_M_start);_M_start=__new_start;_M_finish=__new_finish;_M_end_of_storage=__new_start+__len;}}从提取的vector代码,Part1可看出,push_back的操作行为.兵分两路,可是再向下看,你会发现,无一例外,都通过const_Tp&进行拷贝行为,那么从auto_ptr提出的片段就派上用场了.可你知道的,auto_ptr总是坚持对对象的独权.那必须修改原来维护的对象,而vector行为要求const_Tp&,这样自然会产生问题.一般编译器是可以发觉这种错误的.其实,STL所有的容器类都采用const_Tp&策略.//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++看了sutter和Josuttis的两篇文章中,都提及:
++STL容器不支持auto_ptr原因在于copy的对象只是获得所有权的对象,++这种对象不符合STL的要求.可是本人总感觉即时不是真正的复制对象,++但我用vector>的目的就在于维护对象,并不在乎++所谓的完全对象.而且我用自己写的SmartPointer配合STL容器工作,++很正常.那需要注意的仅仅是const问题.+++//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++no3.这个也是auto_ptr隐含的所有权问题引起的.constauto_ptr不允许修改.随便提及:
const对象不代表对象一点不可以改变.在两种const语义下,都有方法修改对象或对象内部指针维护的对象或其它资源.no4.再看auto_ptr的构析函数.delete不可以消除栈上资源.no5.依赖传入对象指针的构造函数被声明为explicit,禁止隐式转换.3.auto_ptr高级使用指南a.类成员auto_ptr,禁止构造函数以构建"完全对象"Programme1:
structStructx{intm_Idata;charm_CHRdata;/*andsoon*/};出于对象编程的理念,我们将Structx打造成包裹类:
classStructWrapper{private:
Structx*m_STRTxptr;public:
StructWrapper():
m_STRTxptr(newStructx){}~StructWrapper(){deletem_SMRTxptr;}public:
voidSoperator1(){/*针对Structx对象的特性操作*/}voidSoperator2(){/*针对Structx对象的特性操作*/}/*andsoon*/};Programme2:
classStructWrapper{private:
auto_ptrm_SMPTRx;public:
StructWrapp
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 深度探索系列智能指针smartpointer 深度 探索 系列 智能 指针 smartpointer
![提示](https://static.bdocx.com/images/bang_tan.gif)