1. template <typename T>
    2. class smart_ptr {
    3. smart_ptr(smart_ptr&& other) noexcept//拷贝构造参数改为右值引用 变为移动构造函数
    4. {
    5. ptr_ = other.release();
    6. }
    7. smart_ptr& operator=(smart_ptr rhs)//不传入引用而传入对象
    8. {//传入对象构造形参rhs时 因为只定义了移动构造所以在调用op=必须传入右值引用或者右值(临时对象),来构造形参 传入左值会出错
    9. rhs.swap(*this);
    10. return *this;
    11. }
    12. //原
    13. //smart_ptr& operator=(smart_ptr& rhs)
    14. //{
    15. //smart_ptr(rhs).swap(*this);
    16. //return *this;
    17. //}
    18. };


    根据 C++ 的规则,如果我提供了移动构造函数而没有手动提供拷贝构造函数,那后者自动被禁用(记住,C++ 里那些复杂的规则也是为方便编程而设立的)。于是,我们自然地得到了以下结果:

    1. smart_ptr<shape> ptr1{create_shape(shape_type::circle)};//移动构造
    2. smart_ptr<shape> ptr2{ptr1}; // 编译出错 因为没写拷贝构造
    3. smart_ptr<shape> ptr3;
    4. ptr3 = ptr1; // 编译出错 因为没写拷贝构造在调用op=时 无法通过拷贝构造来构造形参
    5. ptr3 = std::move(ptr1); // OK,可以 调用op=时 通过移动构造来构造形参
    6. smart_ptr<shape> ptr4{std::move(ptr3)}; // OK,可以 移动构造

    这也是 C++11 的 unique_ptr 的基本行为。


    子类指针向父类指针的转换(将子类指针强转为父类指针 可实现多态 ) 隐式模板类型转换
    circle(子类指针) 是可以隐式转换成 shape(父类指针) 的,但上面的 smart_ptr 却无法自动转换成 smart_ptr。这个行为显然还是不够“自然”。

    添加一个构造函数,就能实现smart_ptr自动移动成 smart_ptr

    1. template <typename U>
    2. smart_ptr(smart_ptr<U>&& other)
    3. {
    4. ptr_ = other.release();
    5. }

    添加了这个构造函数后,能实现smart_ptr自动(隐式转换)移动成 smart_ptr,但smart_ptr不能移动给smart_ptr兄弟类
    需要注意smart_ptr(smart_ptr&& other)这个函数不会被编译器当作移动构造函数,因而不会自动触发删除拷贝构造函数的行为。如果我们想要实现自动移动,需要显示地将拷贝构造函数标记为=delete,或者定义含模板参数的拷贝构造函数

    引用计数
    上面讲的smart_ptr就是std中unique_ptr,unique_ptr算是较为安全的智能指针。但是一个堆上内存(或者其他资源)只能被单个unique_ptr所拥有—unique_ptr的op= 或者构造 会将右边的资源移到左边,右边的资源指针清为null,这也就导致了只有一个unique_ptr能拥有资源。下面来讲一下std中的shared_ptr,多个shared_ptr智能指针能同时拥有一个堆上内存(或者其他资源)当所有shared_ptr失效(生命周期结束)才会去释放这个资源
    2自己动手来实现一个shared_ptr智能指针3 实现代码 - 图1

    shared_ptr实现共享同一个对象的功能需要同时共享一个计数,记录当前有多少个shared_ptr共享了这一资源,引用计数为1时的这个shared_ptr生命周期结束才释放资源。

    共享引用计数的接口

    1. class shared_count {
    2. public:
    3. shared_count();
    4. void add_count();//增加计数
    5. long reduce_count();//减少计数 需要返回减少后的计数值以便调用者判断 计数是否变为0了
    6. long get_count() const;//返回计数
    7. };


    多线程安全版本的引用计数需要用到一些目前还没学到的知识 先实现一个简单版本的

    1. class shared_count {
    2. public:
    3. //因为在移动构造中有用到下面这些代码 所以全部都需要添加 不会报错的声明noexcept
    4. shared_count() noexcept : count_(1) {}
    5. void add_count() noexcept
    6. {
    7. ++count_;
    8. }
    9. long reduce_count() noexcept
    10. {
    11. return --count_;
    12. }
    13. long get_count() const noexcept
    14. {
    15. return count_;
    16. }
    17. private:
    18. long count_;
    19. };


    实现shared_ptr

    1. template <typename T>
    2. class smart_ptr {
    3. public:
    4. // 模板的各个实例间并不天然就有 friend 关系,
    5. // 因而不能互访私有成员 ptr_ 和 shared_count_。
    6. // 我们需要在 smart_ptr 的定义中显式声明
    7. // smart_ptr<T>和smart_ptr<U>不是同一个类!!!!
    8. template <typename U>
    9. friend class smart_ptr;
    10. explicit smart_ptr(T* ptr = nullptr)
    11. : ptr_(ptr) //explicit 标识该构造函数的调用必须是显示的
    12. //不能隐式调用(传入一个T*指针给一个smart_ptr类型形参 让编译器构造自动调用构造函数去构造这个形参)
    13. {
    14. if (ptr) {
    15. shared_count_ =
    16. new shared_count();
    17. }
    18. }
    19. ~smart_ptr()
    20. {
    21. if (ptr_ &&
    22. !shared_count_
    23. ->reduce_count()) {
    24. //资源ptr存在 并且当前为
    25. //最后一个指向该资源的指针(引用计数为0)才析构释放资源
    26. delete ptr_;
    27. delete shared_count_;
    28. }
    29. }
    30. #include <utility>// std::swap
    31. void swap(smart_ptr& rhs)//用于资源交换
    32. {
    33. using std::swap;
    34. swap(ptr_, rhs.ptr_);
    35. swap(shared_count_,
    36. rhs.shared_count_);
    37. }
    38. smart_ptr(const smart_ptr& other)//拷贝构造
    39. {
    40. //使this 共享 other的资源
    41. ptr_ = other.ptr_;
    42. if (ptr_) {
    43. other.shared_count_
    44. ->add_count();//与other一样指向同一块资源 此资源的引用计数+1
    45. shared_count_ =
    46. other.shared_count_;
    47. }
    48. }
    49. template <typename U>
    50. smart_ptr(const smart_ptr<U>& other) noexcept //隐式类型转换(子类转父类) 拷贝构造
    51. {
    52. //使this 共享 other的资源
    53. ptr_ = other.ptr_;
    54. if (ptr_) {
    55. other.shared_count_
    56. ->add_count();
    57. shared_count_ =
    58. other.shared_count_;
    59. }
    60. }
    61. template <typename U>
    62. smart_ptr(smart_ptr<U>&& other) noexcept
    63. //移动构造的本质是“偷”,所以直接other的资源偷来
    64. //不是与other共享ptr资源而是 直接替代other所以引用计数不需要加
    65. //隐式类型转换(子类转父类) 或者 同类型(U和T的类别一样) 的移动构造
    66. {
    67. ptr_ = other.ptr_;
    68. if (ptr_) {
    69. shared_count_ =
    70. other.shared_count_;
    71. //不是与other共享ptr资源而是 直接替代other所以引用计数不需要加
    72. other.ptr_ = nullptr;//偷走other的资源后 将other的资源置为null
    73. }
    74. }
    75. //为了实现强制的smart_ptr模板参数类型转换,添加下面这个构造函数
    76. //允许在对智能指针内部的指针对象ptr赋值时,
    77. //使用一个现有的智能指针的共享计数
    78. template <typename U>
    79. smart_ptr(const smart_ptr<U>& other,T* ptr) noexcept
    80. {
    81. //将ptr作为资源 将other资源的引用计数+1作为这个ptr的引用计数
    82. ptr_ = ptr; //ptr是外面传进来的,不是other资源指针
    83. if (ptr_) {
    84. other.shared_count_->add_count();
    85. shared_count_ = other.shared_count_;
    86. }
    87. }
    88. //依据传入的实参是右值还是左值来构造形参rhs
    89. //形参得到传入实参的资源后(实参是左值拷贝资源 实参是右值偷走资源)
    90. //与this进行资源的互换 返回this,函数结束
    91. //自动析构形参 因为形参的资源由实参而来 所以函数结束就释放形参资源(引用计数--)
    92. smart_ptr& operator=(smart_ptr rhs) noexcept
    93. {
    94. rhs.swap(*this);
    95. return *this;
    96. }
    97. //返回共享资源指针
    98. T* get() const noexcept { return ptr_; }
    99. //用于调试 返回当前资源ptr的引用计数
    100. long use_count() const noexcept
    101. {
    102. if (ptr_) {
    103. return shared_count_
    104. ->get_count();
    105. } else {
    106. return 0;
    107. }
    108. }
    109. // 添加下面3个操作符重载使smart_ptr行为更像指针
    110. T& operator*() const noexcept { return *ptr_; }
    111. T* operator->() const noexcept { return ptr_; }
    112. operator bool() const noexcept { return ptr_; }
    113. private:
    114. T* ptr_;
    115. shared_count* shared_count_;
    116. };


    强制类型转换 实现父类->子类的强制转换

    1. // 调用时子类是T,父类是U
    2. template <typename T>
    3. void swap(smart_ptr<T>& lhs,
    4. smart_ptr<T>& rhs) noexcept
    5. {
    6. lhs.swap(rhs);
    7. }
    8. template <typename T, typename U>
    9. smart_ptr<T> static_pointer_cast(
    10. const smart_ptr<U>& other) noexcept
    11. {
    12. T* ptr = static_cast<T*>(other.get());
    13. return smart_ptr<T>(other, ptr);
    14. }
    15. template <typename T, typename U>
    16. smart_ptr<T> reinterpret_pointer_cast(
    17. const smart_ptr<U>& other) noexcept
    18. {
    19. T* ptr = reinterpret_cast<T*>(other.get());
    20. return smart_ptr<T>(other, ptr);
    21. }
    22. template <typename T, typename U>
    23. smart_ptr<T> const_pointer_cast(
    24. const smart_ptr<U>& other) noexcept
    25. {
    26. T* ptr = const_cast<T*>(other.get());
    27. return smart_ptr<T>(other, ptr);
    28. }
    29. // smart_ptr<circle> ptr1(new circle());
    30. // smart_ptr<shape> ptr2;
    31. // ptr2 = ptr1;
    32. // smart_ptr<circle> ptr3 = dynamic_pointer_cast<circle>(ptr2);//ptr2 shape->circle 父类转为子类
    33. // 调用时circle是T,shape是U
    34. // printf("use count of ptr3 is %ld\n",ptr3.use_count());//use count of ptr3 is 3
    35. template <typename T, typename U>
    36. smart_ptr<T> dynamic_pointer_cast(
    37. const smart_ptr<U>& other) noexcept
    38. {
    39. T* ptr = dynamic_cast<T*>(other.get());//将other 内部的U* shape* -> T* circle
    40. return smart_ptr<T>(other, ptr);
    41. }