c++ shared_ptr智能指针使用注意事项

上一篇 / 下一篇  2012-09-19 09:30:50 / 个人分类:C++

51Testing软件测试网B_1O4BfB1p3_s_

  shared_ptr在boost中地位相当重要,其行为最接近原始指针,但又比指针更加安全,甚至还能提供基本的线程安全保证。它基本上解决 了在使用c++开发过程中不可避免的使用指针而遇到的许多问题,常见的毫无疑问是内存泄漏和内存的提前释放,还有一些关于指针内存申请而产生的异常问题 等。而要想较好的使用shared_ptr来完全取代指针绝非易事。下面简要说说使用shared_ptr需要注意的问题。51Testing软件测试网O {I7o g:~@F

0D!\8q:jqXw0  1、share_ptr是一个类,它产生的是一个类对象,而不是一个原生的指针对象,但是为了减少类对象与针对对象使用的差异性,所以 share_ptr类故意重载了两种常见的指针操作符: *和->。从而share_ptr与普通指针使用方式一样。简言之,就是share_ptr生成的一个包含类型指针容器对象,它封装了指针对象,对 指针对象负全责,包括生成、释放等;51Testing软件测试网!OVmQ!Q k

51Testing软件测试网udil%u3V,eR

  2、特别需要注意的是,share_ptr的转型函数不能使用c++常用的转型函数,即 static_cast,dynamic_cast,const_cast,而要使用 static_pointer_cast,dynamic_pointer_cast,const_pointer_cast。原因有两 个:static_cast,dynamic_cast,const_cast的功能是转换成对应的模版类型,即 static_cast<T*>其实是转换成类型为T的指针;前面说了share_ptr生成的一个包含类型指针容器对象,使用简单的c++ 转型函数是将share_ptr对象转型为模版指针对象,这完全违背了使用share_ptr的初衷(除非你确确实实有这种需要!),导致转型的模版指针 对象不能采用share_ptr进行管理。因为上面的两个原因:share_ptr为了支持转型,所以提供了类似的转型函数即 static_pointer_cast<T>,从而使转型后仍然为shared_pointer对象,仍然对指针进行管理;51Testing软件测试网_"Q p9pyn5yC w

u0| Yo'_8S2W0  3、share_ptr类重载了许多的构造函数,其中包含无参的构造函数用来创建一个持有空指针的share_ptr对象,,注意它不等价于持 有void*型的指针对象。要想生成一个存储void*型的指针,可以使用share_ptr(void*)构造函数来构造,它相当于一个泛型的指针容 器,拥有容纳任意类型的能力,但是将包含void*指针的shared_ptr对象使用注意2中的转型函数转型为某种类型的指针会使代码不够安全,一般不 要使用;

l W5B(b{Q051Testing软件测试网9n|z"p5Wb

  4、share_ptr完美支持标准容器,并且不需要担心资源泄漏。而标准容易在使用指针对象时需要特别的小心,对指针需要额外的管理。下面用代码范例来演示如何将share_ptr应用与标准容器:

*S0xt U3x|0U2z h051Testing软件测试网 ?x~ JB&{1e$Ce

51Testing软件测试网w/YEb @K~C

<SPAN style="FONT-SIZE: 14px"><STRONG>#include <boost/make_shared.hpp>51Testing软件测试网:t{!m+E.y*G*A
#include <vector>
'P2D/ZdV&Y%X/F0using namespace std;
1FX7b9{'lD0using namespace boost;
~f M~4p m^4D0int main ()51Testing软件测试网;X!u|1W6o X2nR
{
0qUV.F.m'N&EHF0    typedef vector< shared_ptr<int> > sharedContainers;
gDL'b7l#X#Vc0    sharedContainers sharedArray(10);
6c0tb[;]-G `0    for(sharedContainers::interator pos = sharedArray.begin() , int i=0 ;pos!=sharedArray.end();++pos)
*X7_(qRn`%p0     {51Testing软件测试网]^:?'z3lK6{"kr
            *pos = make_shared<int>(++i);
jpk1Yt#]0            cout<<*(*pos)<<"\t";
;^ h S)I$EJ0J(H1v0     }
{l8FIp,C0s0      cout<<endl;
t5~4S0y8jj0}</STRONG></SPAN>

#mR^-e~%R0  注意上面的代码中的头文件#include <boost/make_shared.hpp>,不是常见的#include <boost/smart_ptr.hpp>,这是因为make_shared.hpp中提供了一个自由工厂函数 make_shared<T>(),来消除显示的new调用,其实是模仿了标准库中产生pair的函数make_pair().因为 make_shared.hpp中包含了smart_ptr.hpp,所以加入了make_shared.hpp就不需要再声明 smart_ptr.hpp头文件了。而smart_ptr.hpp没有包含make_shared.hpp,所以必须要单独写出 make_shared.hpp。

[-_o:c*`| r051Testing软件测试网V*eQ:zV.s;C3d&G

  5、share_ptr使用赋值操作符可以从另外一个share_ptr或auto_ptr获得指针的管理权,其行为等同于构造函数,但它完全 不能等同于一种拷贝,只是将原来的对象的引用技术加1,说白了就是共享资源;而实际的指针赋值确是一种浅拷贝操作,关于深拷贝与浅拷贝可参与该篇文章渐析java的浅拷贝和深拷贝。下面用代码范例来share_ptr的赋值和复制操作:(继续上面的例子)

'BK$dE7VQ0

+fc?` M051Testing软件测试网%\4Q h'c:q ~F

O4@oQ+a K S3w0<SPAN style="FONT-SIZE: 14px"><STRONG>#include <boost/make_shared.hpp>51Testing软件测试网E/H`,p7z k Q,ooc
#include <vector>51Testing软件测试网9u _2yM],O
using namespace std;
6U`9t$@1ga0using namespace boost;
51Testing软件测试网o(W Jgr8g

51Testing软件测试网)K)lgoG&M+Inj

int main (int argc, const char * argv[])
Np o~G+m0{
51Testing软件测试网s4U!zj#^ Sv!y

r+u8V7^*{1]dT0    typedef vector< shared_ptr<int> > sharedContainers;51Testing软件测试网6rI[$N._o
    sharedContainers sharedArray(10);51Testing软件测试网9h`"fj%[M/S3| b
    int i=0;51Testing软件测试网t `F Oony\
    for(sharedContainers::iterator pos = sharedArray.begin() ;pos!=sharedArray.end();++pos)51Testing软件测试网 J"J/y@%y!J_a
    {
;]8f(K3ty0        *pos = make_shared<int>(++i);51Testing软件测试网c9c7xE'LOL%BM
    }
MM qf!^o'kYg0    cout<<"sharedArray[5]的初始值:"<<*sharedArray[5]<<endl;51Testing软件测试网?#z(C0ce4\
    cout<<"sharedArray[5]的初始引用计数为:"<<sharedArray[5].use_count()<<endl;
zB6Z?g/k!YGY0    shared_ptr<int> p1 = sharedArray[5];51Testing软件测试网Qw0w[-T+UI-{
    *p1 = 10;51Testing软件测试网 [3}hBHpMTA zZ
    cout<<"sharedArray[5]经过赋值后的值:"<<*sharedArray[5]<<endl;51Testing软件测试网x+Z*t;b%D uB
    cout<<"sharedArray[5]赋值后的引用计数为:"<<sharedArray[5].use_count()<<endl;
mJM'A+p"P)?0    shared_ptr<int> p2(sharedArray[5]);
nF7sm GJ*O0    cout<<"sharedArray[5]复制和赋值后的引用计数为:"<<sharedArray[5].use_count()<<endl;
,A!]-~Uv X+z[$It5y0    cout<<"sharedArray[5]的地址:"<<sharedArray[5]<<",p1的地址:"<<p1<<",p2的地址:"<<p2<<endl;51Testing软件测试网 @5lny{^WB{oTG
    *p2 = 5;51Testing软件测试网&BL!~[ ^
    cout<<"sharedArray[5]经过复制后的值:"<<*sharedArray[5]<<endl;51Testing软件测试网T4t~{!| p
    return 0;51Testing软件测试网o#F-X_/R-F;q)k5g
   
3`~8CI+U)|#?0}</STRONG></SPAN>
51Testing软件测试网 SE(Y$] QQT

?/{(k:O#~)c\b0  其输出结果为:51Testing软件测试网.sakKE `;{6b8foN

W&QZDi0d1z0  sharedArray[5]的初始值:651Testing软件测试网 EB0taTYqK
  sharedArray[5]的初始引用计数为:151Testing软件测试网n6Hf`t&c7J-S)ID
  sharedArray[5]经过赋值后的值:10
G#Z Fy,@#i'?S[2[0  sharedArray[5]赋值后的引用计数为:251Testing软件测试网)Y jo.O;o9}8[
  sharedArray[5]复制和赋值后的引用计数为:3
;O-GR Z{9i0  sharedArray[5]的地址:0x10010092c,p1的地址:0x10010092c,p2的地址:0x10010092c51Testing软件测试网,E'o4?-U EJ|
  sharedArray[5]经过复制后的值:5

8OB _G"k KH}"C7gU0

k1c)t)S+y&v)L7UD0  可以看到,经过赋值和复制后的sharedArray[5],其引用计数增1。而且经过赋值和复制后的sharedArray[5]对象p1和p2所指向的地址完全相同。所以随便改变其中之一的值,另外两个对象指向的值也随之改变,这也是共享资源的精髓吧!

9CE$}8nSjN]!R051Testing软件测试网'|+X~WP.T(u8]

  6、share_ptr针对封装的指针要求,可以定制删除器,即使用构造函数shared_ptr(Y *p , D d)来构造shared_ptr指针。其中第一个参数是要被管理的指针,其含义与其他构造函数一样。而第二个参数,即删除器参数d则告诉 shared_ptr在析构时不是使用普通的delete方法来析构指针p,而是用方法d来操作,即用d(p)来代替delete p。这里的d只需要能够像函数一样被调用,所以d既可以是一个函数对象,也可以是一个函数指针。这种删除器d比较适用于指针对象p在删除时有一定的要求, 例如某中类指针,有专门的析构函数,但切记d的实参对象行为必须与delete一样,不能抛出异常,并且是可拷贝的。51Testing软件测试网BH2FE;B)^6si

51Testing软件测试网;z5TUa5K:g8nN D

  上面说了这么多,其实这只是shared_ptr的一小部分,还有很多涉及c++哲学方面的问题需要注意,例如延时释放、包装成员函数等。51Testing软件测试网9Ji5K1T o.c;M

s!V\1o(C$Qm0  本文如有错误,欢迎指正,对此十分感谢!51Testing软件测试网W Sf0sj


TAG:

 

评分:0

我来说两句

Open Toolbar