├── README.md └── smart_ptr.cpp /README.md: -------------------------------------------------------------------------------- 1 | `std::share_prt` 2 | 3 | `std:unique_ptr` 4 | 5 | `std::weak_ptr` 6 | 7 | ### 深拷贝与浅拷贝 8 | 9 | - 深拷贝优缺点 10 | - 优点:每一个对象(即使是通过拷贝构造函数实例化的对象)的指针都有指向的内存空间,而不是共享,这样在释放的时候就不存在重复释放或者是内存泄漏问题了 11 | - 缺点:内存开销大 12 | - 浅拷贝优缺点 13 | - 通过拷贝构造函数实例化的指针数据变量指向的是共享的内存空间,因此内存开销小。 14 | - 对象析构的时候可能会重复释放或造成内存泄漏。 15 | 16 | ## 引用计数: 17 | 18 | ### 对浅拷贝进行优化 19 | 20 | ```cpp 21 | struct RefValue 22 | { 23 | 24 | RefValue(const char* pszName); 25 | ~RefValue(); 26 | 27 | void AddRef(); 28 | void Release(); 29 | 30 | char* m_pszName; 31 | int m_nCount; 32 | }; 33 | 34 | RefValue::RefValue(const char* pszName) 35 | { 36 | m_pszName = new char[strlen(pszName)+1]; 37 | 38 | m_nCount = 1; 39 | 40 | } 41 | 42 | RefValue::~RefValue() 43 | { 44 | 45 | if (m_pszName != NULL) 46 | { 47 | delete m_pszName; 48 | m_pszName = NULL; 49 | } 50 | } 51 | 52 | void RefValue::AddRef() 53 | { 54 | m_nCount++; 55 | } 56 | 57 | void RefValue::Release() 58 | { 59 | if (--m_nCount == 0) 60 | { 61 | delete this; 62 | } 63 | 64 | } 65 | ``` 66 | 67 | 在进行浅拷贝时加入一个变量保存引用次数,引用一次数值+1,释放一次数值-1,当引用计数为0时,进行delete或者free(); 68 | 69 | 仍然存在的问题: 70 | 71 | - 如果对其中某一个类对象中的资源进行了修改,那么所有引用该资源的对象全部会被修改,这显然是错误的 72 | 73 | ## 写时拷贝: 74 | 75 | 使用引用计数时,当发生共享资源被改变的时候,将共享资源重新复制一份进行修改,不改变共享资源本身。 76 | 77 | ## 智能指针实现: 78 | 79 | 首先一个智能指针是一个类,通过构造函数与析构函数实现资源的分配与回收: 80 | 81 | ```cpp 82 | #include 83 | 84 | using namespace std; 85 | 86 | class smart_ptr{ 87 | public: 88 | explicit smart_ptr(){ 89 | _ptr = new int; 90 | cout<<"alloc ptr."< 121 | 122 | using namespace std; 123 | 124 | class A{ 125 | public: 126 | void get(){ 127 | cout<<"the val of this class is:"< 133 | class smart_ptr{ 134 | public: 135 | explicit smart_ptr(T* ptr = nullptr): _ptr(ptr){ 136 | cout<<"alloc ptr."< ptr(new A); 151 | ptr.get()->get(); 152 | smart_ptr ptr2(new int(5)); 153 | cout<<"the value of ptr2:"<<*(ptr2.get())<() const{ return _ptr;} 178 | ``` 179 | 180 | ```cpp 181 | int main(){ 182 | smart_ptr ptr(new A); 183 | ptr->get(); 184 | (*ptr).get(); 185 | return 0; 186 | } 187 | ``` 188 | 189 | 输出: 190 | 191 | ```cpp 192 | alloc ptr. 193 | the val of this class is:1 194 | the val of this class is:1 195 | delete ptr. 196 | ``` 197 | 198 | ### 拷贝构造和赋值: 199 | 200 | 我们应该如何定义拷贝的行为,假设有如下代码: 201 | 202 | ```cpp 203 | smart_ptr ptr1(new B); //B是A的子类 204 | smart_ptr ptr2{ptr1}; 205 | ``` 206 | 207 | ```cpp 208 | template 209 | class smart_ptr { 210 | … 211 | smart_ptr(smart_ptr& other) 212 | { 213 | ptr_ = other.release();//拷贝构造函数让传入的对象失去所有权,同时拷贝对象接管所有权 214 | } 215 | smart_ptr& operator=(smart_ptr& rhs) 216 | { 217 | //这里首先调用拷贝构造函数创建一个临时类smart_ptr(rhs),this指针和rhs交换 218 | //临时对象拿到this之前维护的指针随着临时对象的析构回收 219 | smart_ptr(rhs).swap(*this); 220 | return *this; 221 | } 222 | … 223 | T* release() 224 | { 225 | T* ptr = ptr_; 226 | ptr_ = nullptr; 227 | return ptr; 228 | } 229 | void swap(smart_ptr& rhs) 230 | { 231 | using std::swap; 232 | swap(ptr_, rhs.ptr_); 233 | } 234 | … 235 | }; 236 | ``` 237 | 238 | ### 移动指针: 239 | 240 | ```cpp 241 | template 242 | class smart_ptr { 243 | … 244 | smart_ptr(smart_ptr&& other) 245 | { 246 | ptr_ = other.release(); 247 | } 248 | smart_ptr& operator=(smart_ptr rhs) 249 | { 250 | smart_ptr(rhs).swap(*this); 251 | return *this; 252 | } 253 | … 254 | }; 255 | ``` 256 | 257 | 修改的地方: 258 | 259 | - 把拷贝构造函数中的参数类型 `smart_ptr&` 改成了 `smart_ptr&&`;现在它成了移动构造函数。 260 | - 把赋值函数中的参数类型 `smart_ptr&` 改成了 `smart_ptr`,在构造参数时直接生成新的智能指针,从而不再需要在函数体中构造临时对象。现在赋值函数的行为是移动还是拷贝,完全依赖于构造参数时走的是移动构造还是拷贝构造。 261 | 262 | 根据 C++ 的规则,如果我提供了移动构造函数而没有手动提供拷贝构造函数,那后者自动被禁用 263 | 264 | ```cpp 265 | int main(){ 266 | smart_ptr ptr1{new B}; 267 | //ptr->get(); 268 | //(*ptr).get(); 269 | smart_ptr ptr2{std::move(ptr1)}; 270 | ptr2->get(); 271 | return 0; 272 | } 273 | ``` 274 | 275 | 输出为: 276 | 277 | ```cpp 278 | alloc ptr. 279 | the val of this class is:1 280 | delete ptr. 281 | delete ptr. 282 | ``` 283 | 284 | ### 子类指针向基类指针的转换: 285 | 286 | ```cpp 287 | template 288 | explicit smart_ptr(smart_ptr&& other){ 289 | _ptr = other.relese(); 290 | } 291 | ``` 292 | 293 | ### 引用计数: 294 | 295 | 上面的智能指针基本完成了unique_ptr的功能,一个对象只能被单个unique_ptr拥有,显然不能满足所有使用场景,一种常见的情况是:多个智能指针同时拥有一个对象,当他们全部失效时,这个对象也同时会被删除,这也就是shared_ptr了。多个不同的shared_ptr不仅可以共享一个对象,同时还应共享同一计数器。 296 | 297 | 计数器接口: 298 | 299 | ```cpp 300 | class share_count{ 301 | public: 302 | share_count(); 303 | void add_account(); 304 | long reduce_count(); 305 | long get_count() const; 306 | }; 307 | ``` 308 | 309 | 这个share_count类除构造函数外有三个方法:增加计数,减少计数,获取计数。增加计数不需要返回值,减少计数需要返回当前计数以判断是不是最后一个共享计数的share_ptr。 310 | 311 | ```cpp 312 | class shared_count{ 313 | public: 314 | shared_count() : _count(1){} 315 | void add_account(){ 316 | ++_count; 317 | } 318 | long reduce_count(){ 319 | return --_count; 320 | } 321 | long get_count() const{ 322 | return _count; 323 | } 324 | 325 | private: 326 | long _count; 327 | }; 328 | ``` 329 | 330 | 加下来我们就可以将引用计数器加入到我们的智能指针里了: 331 | 332 | ```cpp 333 | template 334 | class smart_ptr{ 335 | explicit smart_ptr(T* ptr = nullptr): _ptr(ptr) { 336 | if(ptr){ 337 | _shared_count = new shared_count(); 338 | } 339 | } 340 | ~smart_ptr(){ 341 | if(_ptr && !_shared_count->reduce_count()){ 342 | delete _ptr; 343 | delete _shared_count; 344 | } 345 | } 346 | private: 347 | smart_ptr* _ptr; 348 | shared_count* _shared_count; 349 | }; 350 | ``` 351 | 352 | 逻辑很清晰,当然我们还有更多细节需要处理: 353 | 354 | ```cpp 355 | void swap(smart_ptr& rhs){ 356 | using std::swap; 357 | swap(_ptr, rhs._ptr); 358 | swap(_shared_count, rhs._shared_count); 359 | } 360 | ``` 361 | 362 | 赋值函数可以不变,但是拷贝构造函数和移动构造函数需要更新: 363 | 364 | ```cpp 365 | //赋值函数 366 | smart_ptr& operator=(smart_ptr rhs){ 367 | rhs.swap(*this); 368 | return *this; 369 | } 370 | //拷贝构造函数 371 | smart_ptr(const smart_ptr& other){ 372 | _ptr = other._ptr; 373 | if(_ptr){ 374 | other._shared_count->add_account(); 375 | _shared_count = other._shared_count; 376 | } 377 | } 378 | template 379 | explicit smart_ptr(const smart_ptr& other){ 380 | _ptr = other._ptr; 381 | if(_ptr){ 382 | other._shared_count->add_account(); 383 | _shared_count = other._shared_count; 384 | } 385 | } 386 | //移动构造函数 387 | template 388 | explicit smart_ptr(smart_ptr&& other){ 389 | _ptr = other._ptr; 390 | if(_ptr){ 391 | _shared_count = other._shared_count; 392 | other._ptr = nullptr; 393 | } 394 | } 395 | ``` 396 | 397 | 因为模板的实例之间并不天然就有friend关系,所以上面的代码会报错,我们需要在smart_ptr的定义中显式的声明: 398 | 399 | ```cpp 400 | template 401 | friend class smart_ptr; 402 | ``` 403 | 404 | 添加一个获取当前引用计数的函数: 405 | 406 | ```cpp 407 | long use_count() const{ 408 | if(_ptr){ 409 | return _shared_count->get_count(); 410 | }else{ 411 | return 0; 412 | } 413 | } 414 | ``` 415 | 416 | 测试一下: 417 | 418 | ```cpp 419 | class A{ 420 | public: 421 | void get(){ 422 | cout<<"the val of this class is:"< ptr1{new B}; 439 | cout<<"use count of ptr1 is:"< ptr2; 441 | cout<<"use count of ptr2 is:"< 464 | smart_ptr(const smart_ptr& other, T* ptr){ 465 | _ptr = ptr; 466 | if(_ptr){ 467 | other._shared_count->add_account(); 468 | _shared_count = other._shared_count; 469 | } 470 | } 471 | ``` 472 | 473 | ```cpp 474 | template 475 | smart_ptr dynamic_pointer_cast(const smart_ptr& other){ 476 | T* ptr = dynamic_cast(other.get()); 477 | return smart_ptr(other, ptr); 478 | } 479 | ``` 480 | 481 | 测试: 482 | 483 | ```cpp 484 | int main(){ 485 | smart_ptr ptr1{new B}; 486 | cout<<"use count of ptr1 is:"< ptr2; 488 | cout<<"use count of ptr2 is:"< ptr3 = dynamic_pointer_cast(ptr2); 493 | cout<<"use count of ptr3 is:"< 528 | class smart_ptr{ 529 | public: 530 | template 531 | friend class smart_ptr; 532 | //构造函数 533 | explicit smart_ptr(T* ptr = nullptr): _ptr(ptr) { 534 | if(ptr){ 535 | _shared_count = new shared_count(); 536 | } 537 | } 538 | //智能指针类型转换 539 | template 540 | smart_ptr(const smart_ptr& other, T* ptr){ 541 | _ptr = ptr; 542 | if(_ptr){ 543 | other._shared_count->add_account(); 544 | _shared_count = other._shared_count; 545 | } 546 | } 547 | //赋值函数 548 | smart_ptr& operator=(smart_ptr rhs){ 549 | rhs.swap(*this); 550 | return *this; 551 | } 552 | //拷贝构造函数 553 | smart_ptr(const smart_ptr& other){ 554 | _ptr = other._ptr; 555 | if(_ptr){ 556 | other._shared_count->add_account(); 557 | _shared_count = other._shared_count; 558 | } 559 | } 560 | template 561 | smart_ptr(const smart_ptr& other){ 562 | _ptr = other._ptr; 563 | if(_ptr){ 564 | other._shared_count->add_account(); 565 | _shared_count = other._shared_count; 566 | } 567 | } 568 | //移动构造函数 569 | template 570 | smart_ptr(smart_ptr&& other){ 571 | _ptr = other._ptr; 572 | if(_ptr){ 573 | _shared_count = other._shared_count; 574 | other._ptr = nullptr; 575 | } 576 | } 577 | ~smart_ptr(){ 578 | if(_ptr && !_shared_count->reduce_count()){ 579 | delete _ptr; 580 | delete _shared_count; 581 | } 582 | } 583 | void swap(smart_ptr& rhs){ 584 | using std::swap; 585 | swap(_ptr, rhs._ptr); 586 | swap(_shared_count, rhs._shared_count); 587 | } 588 | long use_count() const{ 589 | if(_ptr){ 590 | return _shared_count->get_count(); 591 | }else{ 592 | return 0; 593 | } 594 | } 595 | /* 596 | * 重载运算符 597 | */ 598 | T& operator*() const{ return *_ptr;} 599 | T* operator->() const{ return _ptr;} 600 | 601 | T* get() const { 602 | return _ptr; 603 | } 604 | private: 605 | T* _ptr; 606 | shared_count* _shared_count; 607 | }; 608 | 609 | template 610 | smart_ptr dynamic_pointer_cast(const smart_ptr& other){ 611 | T* ptr = dynamic_cast(other.get()); 612 | return smart_ptr(other, ptr); 613 | } 614 | ``` 615 | -------------------------------------------------------------------------------- /smart_ptr.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | using namespace std; 4 | 5 | class A{ 6 | public: 7 | void get(){ 8 | cout<<"the val of this class is:"< 24 | class my_shared_ptr{ 25 | public: 26 | /* 27 | * 构造函数 28 | */ 29 | explicit my_shared_ptr(T* ptr = nullptr): _ptr(ptr){ 30 | cout<<"alloc ptr."< 39 | explicit my_shared_ptr(my_shared_ptr&& other){ 40 | _ptr = other.relese(); 41 | } 42 | my_shared_ptr& operator=(my_shared_ptr rhs){ 43 | rhs.swap(*this); 44 | return *this; 45 | } 46 | ~my_shared_ptr(){ 47 | delete _ptr; 48 | cout<<"delete ptr."<() const{ return _ptr;} 64 | T* get(){ 65 | return _ptr; 66 | } 67 | private: 68 | T* _ptr; 69 | }; 70 | class shared_count{ 71 | public: 72 | shared_count() : _count(1){} 73 | void add_account(){ 74 | ++_count; 75 | } 76 | long reduce_count(){ 77 | return --_count; 78 | } 79 | long get_count() const{ 80 | return _count; 81 | } 82 | 83 | private: 84 | long _count; 85 | }; 86 | 87 | 88 | template 89 | class smart_ptr{ 90 | public: 91 | template 92 | friend class smart_ptr; 93 | //构造函数 94 | explicit smart_ptr(T* ptr = nullptr): _ptr(ptr) { 95 | if(ptr){ 96 | _shared_count = new shared_count(); 97 | } 98 | } 99 | //智能指针类型转换 100 | template 101 | smart_ptr(const smart_ptr& other, T* ptr){ 102 | _ptr = ptr; 103 | if(_ptr){ 104 | other._shared_count->add_account(); 105 | _shared_count = other._shared_count; 106 | } 107 | } 108 | //赋值函数 109 | smart_ptr& operator=(smart_ptr rhs){ 110 | rhs.swap(*this); 111 | return *this; 112 | } 113 | //拷贝构造函数 114 | smart_ptr(const smart_ptr& other){ 115 | _ptr = other._ptr; 116 | if(_ptr){ 117 | other._shared_count->add_account(); 118 | _shared_count = other._shared_count; 119 | } 120 | } 121 | template 122 | smart_ptr(const smart_ptr& other){ 123 | _ptr = other._ptr; 124 | if(_ptr){ 125 | other._shared_count->add_account(); 126 | _shared_count = other._shared_count; 127 | } 128 | } 129 | //移动构造函数 130 | template 131 | smart_ptr(smart_ptr&& other){ 132 | _ptr = other._ptr; 133 | if(_ptr){ 134 | _shared_count = other._shared_count; 135 | other._ptr = nullptr; 136 | } 137 | } 138 | ~smart_ptr(){ 139 | if(_ptr && !_shared_count->reduce_count()){ 140 | delete _ptr; 141 | delete _shared_count; 142 | } 143 | } 144 | void swap(smart_ptr& rhs){ 145 | using std::swap; 146 | swap(_ptr, rhs._ptr); 147 | swap(_shared_count, rhs._shared_count); 148 | } 149 | long use_count() const{ 150 | if(_ptr){ 151 | return _shared_count->get_count(); 152 | }else{ 153 | return 0; 154 | } 155 | } 156 | /* 157 | * 重载运算符 158 | */ 159 | T& operator*() const{ return *_ptr;} 160 | T* operator->() const{ return _ptr;} 161 | 162 | T* get() const { 163 | return _ptr; 164 | } 165 | private: 166 | T* _ptr; 167 | shared_count* _shared_count; 168 | }; 169 | 170 | template 171 | smart_ptr dynamic_pointer_cast(const smart_ptr& other){ 172 | T* ptr = dynamic_cast(other.get()); 173 | return smart_ptr(other, ptr); 174 | } 175 | 176 | int main(){ 177 | // my_shared_ptr a{new B}; 178 | // my_shared_ptr b; 179 | // b = a; 180 | smart_ptr ptr1{new B}; 181 | cout<<"use count of ptr1 is:"< ptr2; 183 | cout<<"use count of ptr2 is:"< ptr3 = dynamic_pointer_cast(ptr2); 188 | cout<<"use count of ptr3 is:"<getb(); 190 | return 0; 191 | } 192 | --------------------------------------------------------------------------------