c++智能指针shared_ptr、weak_ptr、unique_ptr

使用c++智能指针需要包含头文件<memory>,对于SGI版本的STL, shared_ptr、weak_ptr实现在<bits/shared_ptr.h>中,unique_ptr实现在<bits/unique_ptr.h>中

 

1、 shared_ptr

  作用:通过应用计数实现自动释放指针,用户不用再去关心资源的释放回收

  注意点:

    a. 指针释放默认使用delete,所以对于不是new的指针,需要在构造函数第二个参数传入释放器,例如对于数组指针

std::shared_ptr<char> shr_p(p, [](char* p) { delete[] p; });

    b. 不要对同一个内置指针通过构造函数或 reset函数生成多个智能指针对象

 

2、 weak_ptr

  作用:是辅助观察shared_ptr,weak_ptr不会影响指针的释放,它的入参只能是shared_ptr或者weak_ptr,在shared_ptr对象全部销毁后,可以用过weak_ptr查看引用                    计数,这样避免了shared_ptr循环应用问题

 

3、 unique_ptr

  作用:高效的唯一指针,析构后会自动释放资源

  注意点:

    a. 它和auto_ptr的区别是,unique_ptr在被拷贝时自身资源也会被swap走,这样就规避了不易发现的浅拷贝导致指针多次释放的问题

    b. 同shared_ptr一样,unique_ptr也是默认使用delete释放资源,所以非new的指针也需要传入个释放器,释放器是在模板入参里传入的

4、shared_ptr和weak_ptr的代码实现及验证

  参考STL源码做一个简单的实现

  1 #include <atomic>
  2 #include <functional>
  3 
  4 template<typename Ptr>
  5 class Sp_counted_base
  6 {
  7 public:
  8     Sp_counted_base(Ptr p)
  9         : m_ptr(p), m_use_count(1), m_weak_count(1){}
 10     Sp_counted_base(Ptr p, std::function<void(Ptr)> func)
 11         : m_ptr(p), m_use_count(1), m_weak_count(1) 
 12     {
 13         m_func = func;
 14     }
 15     // 禁止拷贝
 16     Sp_counted_base(Sp_counted_base const&) = delete;
 17     Sp_counted_base& operator=(Sp_counted_base const&) = delete;
 18     
 19     virtual ~Sp_counted_base() noexcept { }
 20 
 21     // 当引用计数m_use_count为0的时候就释放资源,通过*this
 22     virtual void m_dispose() noexcept
 23     {
 24         std::cout<< "m_dispose"<<std::endl;
 25         if (m_func)
 26         {
 27             m_func(m_ptr);
 28         }
 29         else
 30         {
 31             delete m_ptr;  // 默认使用deleter释放资源
 32         }
 33     }
 34 
 35     // 当引用计数m_weak_count为0的时候就释放资源.
 36     virtual void m_destroy() noexcept
 37     {
 38         delete this;
 39     }
 40 
 41     //引用计数递增
 42     void m_add_ref_copy()
 43     {
 44         m_use_count++;
 45     }
 46 
 47     // 引用计数递减
 48     void m_release() noexcept
 49     {
 50         m_use_count--;
 51         if (m_use_count.load() == 0)
 52         {
 53             m_dispose(); //释放指针数据
 54             m_weak_count--; // shared_ptr销毁时,weak_ptr引用计数减一
 55             if (m_weak_count.load() == 0)
 56             {
 57                 m_destroy();
 58             }
 59         }
 60     }
 61 
 62     // weak_ptr引用计数递增
 63     void m_weak_add_ref() noexcept
 64     {
 65         m_weak_count++;
 66     }
 67 
 68     // weak_ptr引用计数递增
 69     void m_weak_release() noexcept
 70     {
 71         m_weak_count--;
 72         if (m_weak_count.load() == 0)
 73         {
 74             m_destroy(); // 这里只销毁weak_ptr对象,并不会释放资源
 75         }
 76     }
 77     // 获取引用计数
 78     long m_get_use_count() const noexcept
 79     {
 80         return m_use_count.load();
 81     }
 82 
 83 private:
 84     Ptr                    m_ptr;            // 指针数据
 85     std::atomic<int>    m_use_count;    // #shared
 86     std::atomic<int>    m_weak_count;   // #weak + (#shared != 0)
 87     std::function<void(Ptr)>      m_func{}; // 这里用一个回调函数来实现删除器
 88 };
 89 
 90 template<typename Ptr>
 91 class shared_count
 92 {
 93 public:
 94     constexpr shared_count() noexcept : m_pi(0) { }
 95     explicit shared_count(Ptr p) : m_pi(0)
 96     {
 97         m_pi = new Sp_counted_base<Ptr>(p);
 98     }
 99     // 带释放器入参的构造函数
100     explicit shared_count(Ptr p, std::function<void(Ptr)> func) : m_pi(0)
101     {
102         m_pi = new Sp_counted_base<Ptr>(p, func);
103     }
104     
105     ~shared_count() noexcept
106     {
107         if (m_pi != nullptr)
108         {
109             m_pi->m_release();
110         }
111     }
112 
113     shared_count(const shared_count& r) noexcept
114         : m_pi(r.m_pi)
115     {
116         if (m_pi != 0)
117         {
118             m_pi->m_add_ref_copy();
119         }
120     }
121 
122     shared_count& operator=(const shared_count& r) noexcept
123     {
124         Sp_counted_base<Ptr>* tmp = r.m_pi;
125         if (tmp != m_pi)
126         {
127             if (tmp != 0)
128             {
129                 tmp->m_add_ref_copy(); // 被拷贝的对象引用计数++
130             }
131             if (m_pi != 0)
132             {
133                 m_pi->m_release(); // 自身引用计数--
134             }
135             m_pi = tmp;
136         }
137         return *this;
138     }
139 
140     void m_swap(shared_count& r) noexcept
141     {
142         Sp_counted_base<Ptr>* tmp = r.m_pi;
143         r.m_pi = m_pi;
144         m_pi = tmp;
145     }
146 
147     long m_get_use_count() const noexcept
148     {
149         return m_pi != 0 ? m_pi->m_get_use_count() : 0;
150     }
151 
152     bool m_unique() const noexcept
153     {
154         return this->m_get_use_count() == 1;
155     }
156 public:
157     Sp_counted_base<Ptr>*  m_pi;
158 };
159 
160 // shared_ptr的实现
161 template<typename Tp>
162 class My_shared_ptr
163 {
164 public:
165     constexpr My_shared_ptr() noexcept
166         : m_ptr(0), m_refcount() { }
167     explicit My_shared_ptr(Tp* p)
168         : m_ptr(p), m_refcount(p) {}
169     explicit My_shared_ptr(Tp* p, std::function<void(Tp*)> func)
170         : m_ptr(p), m_refcount(p,func) {}
171     // 拷贝构造都用默认函数,引用计数会++
172     My_shared_ptr(const My_shared_ptr&) noexcept = default;
173     My_shared_ptr& operator=(const My_shared_ptr&) noexcept = default;
174     
175     // 移植构造
176     My_shared_ptr(My_shared_ptr<Tp>&& r) noexcept
177         : m_ptr(r.m_ptr), m_refcount()
178     {
179         // 用一个空的m_refcount把r的指针交换过来,引用计数不变
180         m_refcount.m_swap(r.m_refcount);
181         r.m_ptr = 0;
182     }
183     My_shared_ptr& operator=(My_shared_ptr&& r) noexcept
184     {
185         // r的应用计数不变, this指向资源的应用计数--
186         My_shared_ptr(std::move(r)).swap(*this);
187         return *this;
188     }
189     ~My_shared_ptr() = default;
190 
191     void reset() noexcept
192     {
193         // 空对象交换下this,this就变空了,空对象析构,资源指针引用计数--
194         My_shared_ptr().swap(*this);
195     }
196 
197     void reset(Tp* p) // Tp must be complete.
198     {
199         // p和this交换资源,新构造的对象析构,this的应用计数--
200         My_shared_ptr(p).swap(*this);
201     }
202 
203     Tp operator*() const noexcept
204     {
205         return *m_ptr;
206     }
207 
208     Tp* operator->() const noexcept
209     {
210         return m_ptr;
211     }
212     Tp* get() const noexcept
213     {
214         return m_ptr;
215     }
216     long use_count() const noexcept
217     {
218         return m_refcount.m_get_use_count();
219     }
220 
221     void swap(My_shared_ptr<Tp>& other) noexcept
222     {
223         std::swap(m_ptr, other.m_ptr);
224         m_refcount.m_swap(other.m_refcount);
225     }
226     Tp*                       m_ptr;         // Contained pointer.
227     shared_count<Tp*>    m_refcount;    // Reference counter.
228 
229 private:
230 };
231 
232 template<typename Ptr>
233 class weak_count
234 {
235 public:
236     constexpr weak_count() noexcept : m_pi(0) { }
237 
238     weak_count(const shared_count<Ptr>& r) noexcept
239         : m_pi(r.m_pi)
240     {
241         if (m_pi != 0)
242             m_pi->m_weak_add_ref();
243     }
244     weak_count(const weak_count& r) noexcept
245         : m_pi(r.m_pi)
246     {
247         if (m_pi != 0)
248             m_pi->m_weak_add_ref();
249     }
250     ~weak_count() noexcept
251     {
252         if (m_pi != 0)
253             m_pi->m_weak_release();
254     }
255 
256     weak_count& operator=(const shared_count<Ptr>& r) noexcept
257     {
258         Sp_counted_base<Ptr>* tmp = r.m_pi;
259         if (tmp != 0)
260             tmp->m_weak_add_ref();
261         if (m_pi != 0)
262             m_pi->m_weak_release();
263         m_pi = tmp;
264         return *this;
265     }
266 
267     weak_count& operator=(const weak_count& r) noexcept
268     {
269         Sp_counted_base<Ptr>* tmp = r.m_pi;
270         if (tmp != 0)
271             tmp->m_weak_add_ref();
272         if (m_pi != 0)
273             m_pi->m_weak_release();
274         m_pi = tmp;
275         return *this;
276     }
277 
278     void m_swap(weak_count& r) noexcept
279     {
280         Sp_counted_base<Ptr>* tmp = r.m_pi;
281         r.m_pi = m_pi;
282         m_pi = tmp;
283     }
284 
285     long m_get_use_count() const noexcept
286     {
287         return m_pi != 0 ? m_pi->m_get_use_count() : 0;
288     }
289 private:
290     Sp_counted_base<Ptr>*  m_pi;
291 };
292 
293 template<typename Tp>
294 class My_weak_ptr
295 {
296 public:
297     constexpr My_weak_ptr() noexcept
298         : m_ptr(0), m_refcount()
299     { }
300 
301     My_weak_ptr(const My_shared_ptr<Tp>& r) noexcept
302         : m_ptr(r.m_ptr), m_refcount(r.m_refcount)
303     { }
304 
305     My_weak_ptr& operator=(const My_shared_ptr<Tp>& r) noexcept
306     {
307         m_ptr = r.m_ptr;
308         m_refcount = r.m_refcount;
309         return *this;
310     }
311 
312     My_weak_ptr& operator=(const My_weak_ptr<Tp>& r) noexcept
313     {
314         m_ptr = r.m_ptr;
315         m_refcount = r.m_refcount;
316         return *this;
317     }
318     long use_count() const noexcept
319     {
320         return m_refcount.m_get_use_count();
321     }
322 
323     bool
324         expired() const noexcept
325     {
326         return m_refcount.m_get_use_count() == 0;
327     }
328 private:
329     Tp*             m_ptr;                // Contained pointer.
330     weak_count<Tp*>  m_refcount;    // Reference counter.
331 };

main函数

 1 #include <iostream>
 2 #include "My_shared_ptr.h"
 3 struct A
 4 {
 5     ~A()
 6     {
 7         std::cout << "~A" << std::endl;
 8     }
 9 };
10 int main()
11 {
12     My_weak_ptr<A> f;
13     {
14         A* ptr = new A[5];
15         My_shared_ptr <A> a(ptr, [](A* p) {delete[] p; });
16         f = a;
17         std::cout << f.use_count() << std::endl; // 输出1
18         My_shared_ptr<A> b = a;
19         std::cout << f.use_count() << std::endl; // 输出2
20         My_shared_ptr<A> c(a);                     
21         std::cout << f.use_count() << std::endl; // 输出3
22         My_shared_ptr<A> d(std::move(c));
23         std::cout << f.use_count() << std::endl; // 输出3
24         My_shared_ptr<A> e = std::move(d);        
25         std::cout << f.use_count() << std::endl; // 输出3
26 
27     }
28     std::cout << f.use_count() << std::endl;// 输出0
29     return 0;
30 }

 

posted @ 2021-01-30 11:02  ho966  阅读(196)  评论(0编辑  收藏  举报