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 }