qidao123.com ToB IT社区-企服评测·应用市场

 找回密码
 立即注册

C++新特性-智能指针

[复制链接]
发表于 2026-2-9 05:03:38 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
std::weak_ptr

std::weak_ptr是一种弱引用,它不能单独利用,计划之初是为了共同std::shared_ptr,办理后者计划上存在的标题。


  • 利用注意:

    • 不能直接指向原始指针:std::weak_ptr<int> wp (new int);
    • 只能指向std::shared_ptr对象大概std::weak_ptr对象
    • 不增长引用计数
    • 可以用expired()来检测指向的std::shared_ptr管理的对象是否被析构了。
    • 不能直接利用std::shared_ptr管理的对象,如果要利用须要调用lock()。如果底层的对象还没被析构,那么就会返回一个std::shared_ptr指针,指向该对象,否则返回nullptr。

  • 构造函数
    1.     constexpr weak_ptr() noexcept;
    2.     weak_ptr( const weak_ptr& r ) noexcept;
    3.     weak_ptr( weak_ptr&& r ) noexcept;
    4.     template< typename Y >
    5.     weak_ptr( const weak_ptr<Y>& r ) noexcept;
    6.    
    7.     template< typename Y >
    8.     weak_ptr( weak_ptr<Y>&& r ) noexcept;
    9.     template< typename Y >
    10.     weak_ptr( const std::shared_ptr<Y>& r ) noexcept;
    复制代码
    从构造函数可见,std::weak_ptr只能担当std::weak_ptr和std::shared_ptr范例,而不能std::weak_ptr<T> wp (new T);。
    移动语义下的构造函数,构造完成 r 将会变成 nullptr ,不可用。
    std::weak_ptr 的精确利用场景是那些资源如果大概就利用,如果不可利用则不消的场景,它不加入资源的生命周期管理。比方,网络分层结构中,Session 对象(会话对象)利用 Connection 对象(毗连对象)提供的服务工作,但是 Session 对象不管理 Connection 对象的生命周期,Session 管理 Connection 的生命周期是不公道的,由于网络底层堕落会导致 Connection 对象被烧毁,此时 Session 对象如果强行持有 Connection 对象与毕竟抵牾。
  • std::weak_ptr 重要有两个用途:
它只能共同std::shared_ptr利用,不能单独利用。


  • 防止 std::shared_ptr循环引用
    如果两个std::shared_ptr相互引用,那么就会形成一个环,引用计数无法变成0,也会导致内存走漏。
  1.   class Foo : public std::enable_shared_from_this<Foo> {
  2.   public:
  3.     Foo(){ std::cout<<"ctor\n"; }
  4.     ~Foo(){ std::cout<<"dtor\n"; }
  5.     void self()
  6.     {
  7.       fptr_ = shared_from_this();
  8.     }
  9.   private:
  10.     std::shared_ptr<Foo> fptr_; // 改 fptr_ 为 std::weak_ptr 类型即可
  11.   };
  12.   int main() {
  13.     {
  14.     std::shared_ptr<Foo> fptr = std::make_shared<Foo>();
  15.     fptr->self();
  16.     }   
  17.     return 0;
  18.   }
复制代码


  • std::enable_shared_from_this<T>::shared_from_this
    这是个侵入式计划。为的办理传入this导致对象被析构两次的标题。
    什么环境下须要利用 shared_from_this() ??? 用于返回当前对象 *this 的std::shared_ptr范例指针时:
    1.    class Foo : public enable_shared_from_this<Foo>{
    2.    public:
    3.        Foo(){
    4.            std::cout<<"Foo ctor.\n";
    5.        }
    6.        ~Foo(){
    7.            std::cout<<"Foo dtor.\n";
    8.        }
    9.       
    10.        std::shared_ptr<Foo> getSelf(){
    11.            return shared_from_this();
    12.        }
    13.    };
    14.    
    15.    int main() {
    16.        Foo* foo = new Foo;
    17.        std::shared_ptr<Foo> sp1(foo);
    18.        std::shared_ptr<Foo> sp2 = sp1->getSelf();  // 为了对 foo对象进行共享
    19.       
    20.        std::cout<<std::boolalpha;
    21.        std::cout<<(sp2.get()== foo)<<std::endl;
    22.        std::cout<<sp1.use_count()<<std::endl;
    23.    }
    复制代码
    函数原型
    1.    template<typename _Tp>
    2.    class enable_shared_from_this {
    3.    protected:
    4.        ...
    5.    public:
    6.        shared_ptr<_Tp>
    7.        shared_from_this() {
    8.            return shared_ptr<_Tp>(this->_M_weak_this);
    9.        }
    10.        shared_ptr<const _Tp>
    11.        shared_from_this() const {
    12.            return shared_ptr<const _Tp>(this->_M_weak_this);
    13.        }
    14.    private:
    15.        ...
    16.        mutable weak_ptr<_Tp>  _M_weak_this;
    17.    }
    复制代码
    enable_shared_from_this的子类须要返回自身的std::shared_ptr指针,那么就须要继续这个类。
  • 成员变量为什么是weak_ptr范例
    由于如果是std::shared_ptr范例,那么就永久无法析构对象自身。
    这个_M_weak_this不是这个类中初始化,而是在shared_ptr中初始化,初始化的值就是this。因此如果智能指针范例是std::shared_ptr,那么这个类对象一旦创建,引用计数就是1,那么永久也无法析构。
  • 为什么不直接传回this
    std::shared_ptr的引用计数增长是须要用operator=实现的。
    1.     class Foo {/** ... */};
    2.    
    3.     int main() {
    4.         Foo* foo = new Foo;
    5.         std::shared_ptr<Foo> sp1(foo);
    6.         std::shared_ptr<Foo> sp2(foo);
    7.         std::cout<<sp1.use_count()<<std::endl; // 输出是1
    8.     }  
    复制代码
    也就是说,只管sp1和sp2都指向了foo,但是却不共享计数,当析构的时间就会被析构两次,产生未界说举动。
    std::weak_ptr可以担当std::shared_ptr参数来构造自己,std::shared_ptr也具有担当std::weak_ptr参数来构造自己。
智能指针标题



  • share_ptr 与unique_ptr区别
    重要在于前者接纳引用技能实现对象共享,redis里的对象管理也是接纳这个。而后者只能独占,不能赋值/复制,只能移动,由于其拷贝构造函数和赋值函数被禁用了。
    在std::unique_ptr内部:
    1.     // Disable copy from lvalue.
    2.     unique_ptr(const unique_ptr&) = delete;
    3.     unique_ptr& operator=(const unique_ptr&) = delete;
    复制代码
参考



  • 循环引用
  • shared_from_tbis
shared_ptr 指向一个动态数组须要注意什么?

析构器须要设置为 delete[]。而uniqued_ptr的的默认析构器模板类std::default_delete,能自动设别new int和new int[]由于不消担心。
  1.   template< class Y > explicit shared_ptr( Y* ptr );
  2.   template< class Y, class Deleter >  shared_ptr( Y* ptr, Deleter d )
复制代码
上面一个,默认的析构器是delete ptr。当 Y* ptr = new Y[x],析构器也须要重置。
  1.   #include <memory>
  2.   #include <vector>
  3.   #include <algorithm>
  4.   
  5.   int main() {
  6.   //   {
  7.   //        std::shared_ptr<int> shared_bad(new int[10]);
  8.   //    } // 析构函数调用 delete ,未定义行为
  9.   
  10.       {
  11.           std::shared_ptr<int> shared_good(new int[10], std::default_delete<int[]>());
  12.       } // 析构函数调用 delete[] , ok
  13.   
  14.       {
  15.           std::unique_ptr<int> ptr(new int(5));
  16.       } // unique_ptr<int> 使用 default_delete<int>
  17.   
  18.       {
  19.           std::unique_ptr<int[]> ptr(new int[10]);
  20.       } // unique_ptr<int[]> 使用 default_delete<int[]>
  21.   }
复制代码
std::shared_ptr 线程安全

std::shared_ptr的引用计数自己是安全且无锁的,但对象的读写则不是。也就是说std::shared_ptr对象的创建析构是线程安全的,但是多线程读写std::shared_ptr对象不是线程安全的。std::shared_ptr 内存是由于两个构成部门: 指向管理对象的指针 和 引用计数器。在读/写时,是直接对两个变量利用,不大概是原子范例的。由于 std::shared_ptr 有两个数据成员,读写利用不能原子化.使得多线程读写同一个 std::shared_ptr 对象须要加锁.
std::weak_ptr的实现原理

std::weak_ptr 是为了办理 std::shared_ptr 循环引用而生,构造 std::weak_ptr 对象只能通过 std::shared_ptr 来构造,但是std::weak_ptr 对象的生命周期对相应的 std::shared_ptr的引用计数不产生影响,即不增长大概镌汰引用计数。
std::weak_ptr的引用计数部门也是有锁利用,因此 std::weak_ptr 对象生命周期的构造与烧毁都是线程安全的。
  1.         // 基类
  2.     template<typename _Tp, _Lock_policy _Lp>
  3.     class __weak_ptr
  4.     {
  5.       template<typename _Yp, typename _Res = void>
  6.           using _Compatible = typename enable_if<__sp_compatible_with<_Yp*, _Tp*>::value, _Res>::type;
  7.       // Constraint for assignment from shared_ptr and weak_ptr:
  8.       template<typename _Yp>
  9.       using _Assignable = _Compatible<_Yp, __weak_ptr&>;
  10.     public:
  11.       using element_type = typename remove_extent<_Tp>::type;
  12.       constexpr __weak_ptr() noexcept
  13.       : _M_ptr(nullptr), _M_refcount()
  14.       { }
  15.       __weak_ptr(const __weak_ptr&) noexcept = default;
  16.       ~__weak_ptr() = default;
  17.       // The "obvious" converting constructor implementation:
  18.       //
  19.       //  template<typename _Tp1>
  20.       //  __weak_ptr(const __weak_ptr<_Tp1, _Lp>& __r)
  21.       //  : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount) // never throws
  22.       //  { }
  23.       //
  24.       // has a serious problem.
  25.       //
  26.       //  __r._M_ptr may already have been invalidated. The _M_ptr(__r._M_ptr)
  27.       //  conversion may require access to *__r._M_ptr (virtual inheritance).
  28.       //
  29.       // It is not possible to avoid spurious access violations since
  30.       // in multithreaded programs __r._M_ptr may be invalidated at any point.
  31.       template<typename _Yp, typename = _Compatible<_Yp>>
  32.       __weak_ptr(const __weak_ptr<_Yp, _Lp>& __r) noexcept
  33.       : _M_refcount(__r._M_refcount)
  34.        { _M_ptr = __r.lock().get(); }
  35.       template<typename _Yp, typename = _Compatible<_Yp>>
  36.       __weak_ptr(const __shared_ptr<_Yp, _Lp>& __r) noexcept
  37.       : _M_ptr(__r._M_ptr), _M_refcount(__r._M_refcount)
  38.       { }
  39.       __weak_ptr(__weak_ptr&& __r) noexcept
  40.       : _M_ptr(__r._M_ptr), _M_refcount(std::move(__r._M_refcount))
  41.       { __r._M_ptr = nullptr; }
  42.       template<typename _Yp, typename = _Compatible<_Yp>>
  43.       __weak_ptr(__weak_ptr<_Yp, _Lp>&& __r) noexcept
  44.       : _M_ptr(__r.lock().get()), _M_refcount(std::move(__r._M_refcount))
  45.       { __r._M_ptr = nullptr; }
  46.       __weak_ptr&
  47.       operator=(const __weak_ptr& __r) noexcept = default;
  48.       template<typename _Yp>
  49.       _Assignable<_Yp>
  50.       operator=(const __weak_ptr<_Yp, _Lp>& __r) noexcept
  51.       {
  52.         _M_ptr = __r.lock().get();
  53.         _M_refcount = __r._M_refcount;
  54.         return *this;
  55.       }
  56.       template<typename _Yp>
  57.       _Assignable<_Yp>
  58.       operator=(const __shared_ptr<_Yp, _Lp>& __r) noexcept
  59.       {
  60.         _M_ptr      = __r._M_ptr;
  61.         _M_refcount = __r._M_refcount;
  62.         return *this;
  63.       }
  64.       __weak_ptr&
  65.       operator=(__weak_ptr&& __r) noexcept
  66.       {
  67.         _M_ptr      = __r._M_ptr;
  68.         _M_refcount = std::move(__r._M_refcount);
  69.         __r._M_ptr  = nullptr;
  70.         return *this;
  71.       }
  72.       template<typename _Yp>
  73.       _Assignable<_Yp>
  74.       operator=(__weak_ptr<_Yp, _Lp>&& __r) noexcept
  75.       {
  76.         _M_ptr      = __r.lock().get();
  77.         _M_refcount = std::move(__r._M_refcount);
  78.         __r._M_ptr  = nullptr;
  79.         return *this;
  80.       }
  81.       __shared_ptr<_Tp, _Lp> lock() const noexcept
  82.       { return __shared_ptr<element_type, _Lp>(*this, std::nothrow); }
  83.       long use_count() const noexcept
  84.       { return _M_refcount._M_get_use_count(); }
  85.       bool expired() const noexcept
  86.       { return _M_refcount._M_get_use_count() == 0; }
  87.       template<typename _Tp1>
  88.       bool owner_before(const __shared_ptr<_Tp1, _Lp>& __rhs) const noexcept
  89.       { return _M_refcount._M_less(__rhs._M_refcount); }
  90.       template<typename _Tp1>
  91.       bool owner_before(const __weak_ptr<_Tp1, _Lp>& __rhs) const noexcept
  92.       { return _M_refcount._M_less(__rhs._M_refcount); }
  93.       void reset() noexcept
  94.       { __weak_ptr().swap(*this); }
  95.       void swap(__weak_ptr& __s) noexcept
  96.       {
  97.         std::swap(_M_ptr, __s._M_ptr);
  98.         _M_refcount._M_swap(__s._M_refcount);
  99.       }
  100.     private:
  101.       // Used by __enable_shared_from_this.
  102.       void _M_assign(_Tp* __ptr, const __shared_count<_Lp>& __refcount) noexcept
  103.       {
  104.         if (use_count() == 0)
  105.           {
  106.             _M_ptr = __ptr;
  107.             _M_refcount = __refcount;
  108.           }
  109.       }
  110.       template<typename _Tp1, _Lock_policy _Lp1> friend class __shared_ptr;
  111.       template<typename _Tp1, _Lock_policy _Lp1> friend class __weak_ptr;
  112.       friend class __enable_shared_from_this<_Tp, _Lp>;
  113.       friend class enable_shared_from_this<_Tp>;
  114.       element_type*                  _M_ptr;                // Contained pointer.
  115.       __weak_count<_Lp>  _M_refcount;    // Reference counter.
  116.     };
  117.   /**
  118.    *  @brief  A smart pointer with weak semantics.
  119.    *
  120.    *  With forwarding constructors and assignment operators.
  121.    */
  122.     template<typename _Tp>
  123.     class weak_ptr : public __weak_ptr<_Tp>
  124.     {
  125.       template<typename _Arg>
  126.       using _Constructible = typename enable_if<is_constructible<__weak_ptr<_Tp>, _Arg>::value>::type;
  127.       template<typename _Arg>
  128.       using _Assignable = typename enable_if<is_assignable<__weak_ptr<_Tp>&, _Arg>::value, weak_ptr&>::type;
  129.     public:
  130.       constexpr weak_ptr() noexcept = default;
  131.       template<typename _Yp,
  132.       typename = _Constructible<const shared_ptr<_Yp>&>>
  133.       weak_ptr(const shared_ptr<_Yp>& __r) noexcept
  134.       : __weak_ptr<_Tp>(__r) { }
  135.       weak_ptr(const weak_ptr&) noexcept = default;
  136.       template<typename _Yp, typename = _Constructible<const weak_ptr<_Yp>&>>
  137.       weak_ptr(const weak_ptr<_Yp>& __r) noexcept
  138.       : __weak_ptr<_Tp>(__r) { }
  139.       weak_ptr(weak_ptr&&) noexcept = default;
  140.       template<typename _Yp, typename = _Constructible<weak_ptr<_Yp>>>
  141.       weak_ptr(weak_ptr<_Yp>&& __r) noexcept
  142.       : __weak_ptr<_Tp>(std::move(__r)) { }
  143.       weak_ptr&
  144.       operator=(const weak_ptr& __r) noexcept = default;
  145.       template<typename _Yp>
  146.       _Assignable<const weak_ptr<_Yp>&>
  147.       operator=(const weak_ptr<_Yp>& __r) noexcept
  148.       {
  149.         this->__weak_ptr<_Tp>::operator=(__r);
  150.         return *this;
  151.       }
  152.       template<typename _Yp>
  153.       _Assignable<const shared_ptr<_Yp>&>
  154.       operator=(const shared_ptr<_Yp>& __r) noexcept
  155.       {
  156.         this->__weak_ptr<_Tp>::operator=(__r);
  157.         return *this;
  158.       }
  159.       weak_ptr&
  160.       operator=(weak_ptr&& __r) noexcept = default;
  161.       template<typename _Yp>
  162.       _Assignable<weak_ptr<_Yp>>
  163.       operator=(weak_ptr<_Yp>&& __r) noexcept
  164.       {
  165.         this->__weak_ptr<_Tp>::operator=(std::move(__r));
  166.         return *this;
  167.       }
  168.       shared_ptr<_Tp> lock() const noexcept
  169.       { return shared_ptr<_Tp>(*this, std::nothrow); }
  170.     };
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录

QQ|手机版|qidao123.com IT社区;IT企服评测▪应用市场 ( 浙ICP备20004199|浙ICP备20004199号 )|网站地图

GMT+8, 2026-3-11 11:44 , Processed in 0.220387 second(s), 31 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表