转自 http://blog.csdn.net/u013696062/article/details/39665247

Share_ptr也是一种智能指针。类比于auto_ptr学习。所以推荐先学习auto_ptr,再来学习shared_ptr。本博客的前两个就是auto_ptr的总结。希望感兴趣的朋友可以看看。

Shared_ptr和auto_ptr最大的区别就是,shared_ptr解决了指针间共享对象所有权的问题,也就是auto_ptr中的赋值的奇怪问题。所以满足了容器的要求,可以用于容器中。而auto_ptr显然禁止共享对象所有权,不可以用于容器中。

  1. int * a=new int(2);
  2. shared_ptr<int> sp1(a);
  3. shared_ptr<int> sp2(sp1);     OK

当然shared_ptr作为一种智能指针,也拥有和shared_ptr一些相似的性质。它们本质上都是类,但是使用起来像指针。它们都是为了解决防止内存泄漏的解决方案。都是运用了RAII技术来实现的。

注意:使用shared_ptr也要引用头文件#include<memory>

由于shared_ptr的源码过于复杂,我们不给出源码。类比于auto_ptr学习.

1. 首先类shared_ptr有两个成员变量。T * px和unsign long * pn;

T * px;显然和auto_ptr一样,用于储存对象的指针。

pn用于记录有多少个shared_ptr拥有同一个对象。pn是shared_ptr对象间共享的,类似于static成员变量。

  1. template<class T>
  2. class shared_ptr{
  3. private:
  4. T *px; // contained pointer
  5. unsignedlong* pn; // reference counter
  6. }

总结:其实shared_ptr的原理,就是使用px来记录指针,使用*pn来记录px指向的对象的拥有者share_ptr的个数,当一个shared_ptr对象达到作用域时,不会释放资源,只有当*pn变为0的时候,才会释放指针指向的资源。

2. 一个简单实现的源码(仍然看懂源码还是最重要的。

  1. #pragma once
  2. //shared_ptr的简单实现版本
  3. //基于引用记数的智能指针
  4. //它可以和stl容器完美的配合
  5. namespace boost
  6. {
  7. template<class T>
  8. class shared_ptr
  9. {
  10. typedef unsigned longsize_type;
  11. private:
  12. T *px; // contained pointer
  13. size_type* pn; // reference counter
  14. public:
  15. //构造函数---------------------------------------------------2
  16. /*
  17. int* a=new int(2);
  18. shared_ptr<int> sp;
  19. shared_ptr<int> sp(a);
  20. */
  21. explicitshared_ptr(T* p=0) : px(p)
  22. {
  23. pn = new size_type(1);
  24. }
  25. /*
  26. Derived d;
  27. shared_ptr<Base> ap(d);
  28. */
  29. template<typename Y>
  30. shared_ptr(Y* py)
  31. {
  32. pn = newsize_type(1);
  33. px=py;
  34. }
  35. //copy构造函数------------------------------------------------
  36. /*
  37. int * a=new int;
  38. shared_ptr<int> sp(a);
  39. shared_ptr<int> sp1(sp);
  40. */
  41. shared_ptr(constshared_ptr& r) throw(): px(r.px)
  42. {
  43. ++*r.pn;
  44. pn = r.pn;
  45. }
  46. /*
  47. shared_ptr<Derived>sp1(derived);
  48. shared_ptr<Base> sp2(sp1);
  49. */
  50. template<typename Y>
  51. shared_ptr(constshared_ptr<Y>& r)//用于多态
  52. {
  53. px = r.px;
  54. ++*r.pn;
  55. pn = r.pn; //shared_count::op= doesn't throw
  56. }
  57. //重载赋值operator=--------------------------------------------
  58. shared_ptr& operator=(const shared_ptr& r) throw()
  59. {
  60. if(this== &r) return *this;
  61. dispose();
  62. px = r.px;
  63. ++*r.pn;
  64. pn = r.pn;
  65. return *this;
  66. }
  67. template<typename Y>
  68. shared_ptr& operator=(const shared_ptr<Y>& r)//用于多态
  69. {
  70. dispose();
  71. px = r.px;
  72. ++*r.pn;
  73. pn = r.pn; //shared_count::op= doesn't throw
  74. return *this;
  75. }
  76. ~shared_ptr() { dispose(); }
  77. void reset(T* p=0)
  78. {
  79. if ( px == p ) return;
  80. if (--*pn == 0)
  81. { delete(px); }
  82. else
  83. { // allocate newreference
  84. // counter
  85. // fix: prevent leak if new throws
  86. try { pn = new size_type; }
  87. catch (...) {
  88. // undo effect of —*pn above to
  89. // meet effects guarantee
  90. ++*pn;
  91. delete(p);
  92. throw;
  93. } // catch
  94. } // allocate newreference counter
  95. *pn = 1;
  96. px = p;
  97. } // reset
  98. reference operator*()const throw(){ return *px; }
  99. pointer operator->()const throw(){ return px; }
  100. pointer get() constthrow(){ returnpx; }
  101. size_type use_count() constthrow()//
  102. { return *pn; }
  103. bool unique() const throw()//
  104. { return *pn ==1; }
  105. private:
  106. void dispose() throw()
  107. {
  108. if (--*pn == 0)
  109. { delete px; delete pn; }
  110. }
  111. }; // shared_ptr
  112. template<typename A,typenameB>
  113. inline bool operator==(shared_ptr<A>const & l, shared_ptr<B> const & r)
  114. {
  115. return l.get() == r.get();
  116. }
  117. template<typename A,typenameB>
  118. inline bool operator!=(shared_ptr<A>const & l, shared_ptr<B> const & r)
  119. {
  120. return l.get() != r.get();
  121. }
  122. }//namespace boost

要注意的地方:

3. Shared_ptr和auto_ptr都有类似的规定:

看看它们的copy构造和重载赋值都可以看出:

不允许

  1. int* a=new int(2);
  2. shared_ptr<int>sp=a;//  error
  3. sp=a;//    error

就是不允许使用一个纯指针给一个智能指针赋值或copy构造。只能使用智能指针给另一个智能指针赋值或copy构造。

  1. int* a=new int(2);
  2. hared_ptr<int> sp(a);//构造函数
  3. shared_ptr<int> sp1(sp);//copy构造
  4. sp1=sp;//赋值

在auto_ptr中也是相同的。

4. 注意shared_ptr的几个函数

Ø     Reset()函数:重置函数

标准中的是:

  1. int* a=new int(2);
  2. int* b=new int(3);
  3. shared_ptr<int> sp2(a);
  4. shared_ptr<int> sp1(a);
  5. shared_ptr<int> sp(a);
  6. sp.reset(b);
  7. sp.reset();
  8. sp.reset(sp2);  -----!!!也是可以的。

使得sp获得b的拥有权。失去a的拥有权。注意这会使得a的拥有者少1.当a的拥有者变为0时,就会释放a的资源。

Ø     Swap()函数:交换函数

  1. int* a=new int(2);
  2. shared_ptr<int> sp(a);
  3. shared_ptr<int> sp1(a);
  4. sp.swap(sp1);

就是两个shared_ptr中的px和pn都互换一下。

Ø     Get()函数:返回px

Ø     Use_count函数:返回*pn,就是对象的拥有者的数量。

Ø     Unique函数:令*pn=1;让对象的拥有者的数量变为1。返回bool

Ø     同时share_ptr也重载了*和->

5. tr1中重载了几个有关shared_ptr的符号:

template<classT, class U>

booloperator==(shared_ptr<T> const& a, shared_ptr<U> const& b);

转自 http://blog.csdn.net/u013696062/article/details/39665247

判断拥有的对象是否是一样的

template<classT, class U>

bool operator!=(shared_ptr<T> const&a, shared_ptr<U> const& b);

判断拥有的对象是否是不一样的

template<classT, class U>

bool operator<(shared_ptr<T>const& a, shared_ptr<U> const& b);

重载了小于号,在STL中的LIST中非常有用。

  1. int* a=new int(2);
  2. int* b=new int(3);
  3. shared_ptr<int> sp(a);
  4. shared_ptr<int> sp1(b);
  5. if(sp<sp1)
  6. cout<<"2222"<<endl;

6. 注意真实中shared_ptr中没有public dispose这个函数,这里只是为了避免代码重复。

7. 注意shared_ptr中的析构函数中不是直接释放资源,而是调用了dispose函数,如果*pn==0了,才会释放资源。

8.shared_ptr的多线程的安全性

shared_ptr 本身不是 100%线程安全的。它的引用计数本身是安全且无锁的,但对象的读写则不是,因为shared_ptr有两个数据成员,读写操作不能原子化。根据文档,shared_ptr的线程安全级别和内建类型、标准库容器、string一样,即:

  • 一个 shared_ptr 实体可被多个线程同时读取;
  • 两个的 shared_ptr 实体可以被两个线程同时写入,“析构”算写操作;
  • 如果要从多个线程读写同一个 shared_ptr 对象,那么需要加锁。

发现了两个非常有意思的东西:

1. 看tr1中的源码中发现两个这样的东西:

template<class Y, classD> shared_ptr(Y * p, D d);

template<class Y, classD> void reset(Y * p, D d);

其中的D d是个什么东西?源码的解释是d是一个deleter(删除器)。至此我们突然发现我们可以给shared_ptr指定一个删除器,当*pn==0的时候,不去释放资源,而去调用我们自己给它的删除器。

当shared_ptr的引用次数为0的时候,share_ptr就会调用释放函数来释放资源。

当我们希望引用次数为0的时候,shared_ptr不释放资源,而是调用我们指定的操作的时候,就会用到D d;

  1. void foo(int * d)
  2. {
  3. cout<<"1234"<<endl;
  4. }
  5. int _tmain(int argc, _TCHAR* argv[])
  6. {
  7. int* a=new int(2);
  8. shared_ptr<int> sp(a,foo);
  9. shared_ptr<int> sp1(sp);
  10. sp.reset();
  11. sp1.reset();
  12. //_CrtDumpMemoryLeaks();
  13. system("pause");
  14. return 0;
  15. }

注意!:

1. 指定的删除器的参数必须是int*;和shared_ptr<int>中的int对应。不能是其他的,或者为空也是错的。因为系统会把shared_ptr的对象px赋给删除器的参数,我们也可以在删除器中释放资源。

2. 只有a的引用次数为0才会调用,所以如果没有sp1.reset()。也不会调用foo函数。

2. 使用shared_ptr的时候,要小心,想一想操作的内在含义才去做。

1>

  1. int* a=new int(2);
  2. shared_ptr<int> sp(a);
  3. shared_ptr<int> sp1(sp);
  4. sp.reset();//--------(1)
  5. sp.reset();//--------(2)

这里(1)是重置了sp,注意(2)是没有任何作用的,不能使得a的引用次数变为0.想一想reset的函数内部,(2)的时候,sp中的对象pn已经为空了,则不能改变*pn的值了。

2>

  1. int* a=new int(2);
  2. shared_ptr<int> sp(a);//----------(1)
  3. shared_ptr<int> sp1(a);//---------(2)

注意:这里的(2)也是不对的。想一想shared_ptr的构造函数,(1)的时候,sp的px指向a,且*pn为1.而(2)的时候,px指向a,且*pn也是1.这显然就问题了。a被引用了2次,但是*pn为1.在最后作用域达到的时候,就会释放2次内存,这就会引发异常。

总结:shared_ptr和auto_ptr的区别。

Shared_ptr有两个变量,一个记录对象地址,一个记录引用次数

Auto_ptr只有一个变量,用来记录对象地址

Shared_ptr可用多个shared_ptr拥有一个资源。

Auto_ptr只能一个auto_ptr拥有一个资源

Shared_ptr可以实现赋值的正常操作,使得两个地址指向同一资源

Auto_ptr的赋值很奇怪,源失去资源拥有权,目标获取资源拥有权

Shared_ptr到达作用域时,不一定会释放资源。

Auto_ptr到达作用于时,一定会释放资源。

Shared_ptr存在多线程的安全性问题,而auto_ptr没有。

Shared_ptr可用于容器中,而auto_ptr一般不可以用于容器中。

Shared_ptr可以在构造函数、reset函数的时候允许指定删除器。而auto_ptr不能。

还有这里说一句:使用智能指针(不管shared_ptr还是auto_ptr),都要清除源码内部的实现原理,使用起来才不会错。而且使用的时候,一定要想一想函数内部的实现原理再去使用。切记小心。

C++之shared_ptr总结的更多相关文章

  1. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  2. 智能指针shared_ptr的用法

    为了解决C++内存泄漏的问题,C++11引入了智能指针(Smart Pointer). 智能指针的原理是,接受一个申请好的内存地址,构造一个保存在栈上的智能指针对象,当程序退出栈的作用域范围后,由于栈 ...

  3. shared_ptr

    省去对象指针的显示delete typedef tr1::shared_ptr<int> IntPtr; IntPtr fun() { IntPtr p = new int(3); ret ...

  4. 如何用shared_ptr减少锁的争用

    在并发环境下锁的使用是家常便饭, 如何减少锁的使用是优化程序性能的一个方面. c++11里面新增了智能指针std::shared_ptr, 这个东西也许能给我们带来些启发. shared_ptr的一个 ...

  5. C++ 之 auto_ptr and shared_ptr

    1.auto_ptr 这个所谓的只能指针有点鸡肋!  没有引用计数,而且还有一个所有权转移的情况! 当所有权转移后,以前的auto_ptr将会成为null 2.shared_ptr 增加了引用计数,没 ...

  6. shared_ptr和多线程

    前一篇文章写得实在太挫,重新来一篇. 多线程环境下生命周期的管理 多线程环境下,跨线程对象的生命周期管理会有什么挑战?我们拿生产者消费者模型来讨论这个问题. 实现一个简单的用于生产者消费者模型的队列 ...

  7. shared_ptr:资源管理利器

    如果你还在使用传统的C++,那么可以肯定堆内存的管理让你头痛过!在传统的C++领域,堆内存管理上我们能借用的现成工具就只有auto_ptr.但是很不幸用auto_ptr管理堆内存简直就是个错误.aut ...

  8. shared_ptr 线程安全

    Then what's really happening is TWO different sections of memory are being allocated. It's done at o ...

  9. shared_ptr 和 unique_ptr

    c++11标准废除乐auto_ptr, C++ 标准库智能指针 使用这些智能指针作为将指针封装为纯旧 C++ 对象 (POCO) 的首选项. unique_ptr 只允许基础指针的一个所有者. 除非你 ...

  10. c++ shared_ptr 使用注意事项. 2

    1.抛弃临时对象,让所有的智能指针都有名字. 2.类向外传递 this 的  shared_ptr 让类继承   enable_shared_from_this. 然后返回  shared_from_ ...

随机推荐

  1. Apache中 RewriteCond 规则参数介绍 转

    摘要: RewriteCond指令定义了规则生效的条件,即在一个RewriteRule指令之前可以有一个或多个RewriteCond指令.条件之后的重写规则仅在当前URI与Pattern匹配并且满足此 ...

  2. Microsoft Office 2013 (64位) 免费完整版(安装 + 激活)

    Microsoft Office 2013(Office 15)是微软的新一代Office办公软件,全面采用Metro界面.Microsoft Office 2013官方下载(Office2013专业 ...

  3. Adobe Fireworks CS6是一款集网页图片设计、制作与编辑为一体的专业软件

    Adobe Fireworks CS6是一款集网页图片设计.制作与编辑为一体的专业软件,它不仅可以轻松制作出各种动感的Gif.动态按钮.动态翻转等网络图片,还可以轻松实现大图切割,让网页加载的图片显示 ...

  4. C# 在类文件自动添加文件注释的方法

    对于vs2013来讲, 步骤: 1.VS2013 中找到(安装盘符以C盘为例)C:\ProgramFiles(x86)\Microsoft VisualStudio12.0\Common7\IDE\I ...

  5. 【LeetCode】129. Sum Root to Leaf Numbers

    Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represent a number ...

  6. Vue.js 中的动态路由

    静态路由是不可以传递参数的.需要传递参数得用到动态路由 那么如何将参数作为路由呢? //在参数名前面加上 : ,然后将参数写在路由的 path 内 routes: [ //将页面组件与path指令的路 ...

  7. mysql中OPTIMIZE TABLE的作用及使用

    来看看手册中关于 OPTIMIZE 的描述: OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ... 如果您已经删除 ...

  8. Maven项目中突然找不到Build Path或maven dependencies library

    这两天发现有个maven项目抽风了,一个是右击项目找不到Build Path了,一个是依赖的lib库没了,maven引入的依赖包导不了.后来发现是eclipse搞的鬼,出问题的是项目下的.classp ...

  9. Python学习书籍推荐 中英对照

    Learn Python The Hard Way 笨办法学 python A Byte of Python 简明Python教程 初学者 英文版 Learning Python, 3rd Editi ...

  10. java.sql.SQLException: 无法转换为内部表示

    1. 我出这个错代码:wfef.setRow_num(rs.getInt(rs.getInt(12))); 2. 分析:rs.getInt(12)  得到的是int类型,rs.getInt(rs.ge ...