weak_ptr源码分析

shared_ptr源码分析后续 上次剖析了shared_ptr类的源码,本来肯定也是要说shared_count的,不过由于篇幅,shared_count在这篇博客分析。shared_ptr类自身有两个成员,一个就是T类型指针,另一个就是shared_count对象了。shared_ptr把所有的计数任务都交给了该成员,最终指针的销毁也是由该对象去执行的(底层实际还有sp_counted_base)。这是一种解耦的思想。  源码 阅读详情

之前分析了shared_ptr的框架,这次来说一下shared_ptr的兄弟weak_ptr,它们常常是一起出现的。

weak_ptr顾名思义就是弱指针,它不会增加对象的引用计数,欸有重载operator*和operator->,使用时,应当通过weak_ptr的lock函数构造一个shared_ptr。

作用:防止循环引用(以后博客分析)。应用:在enable_shared_from_this类中,它有一个weak_ptr weak_this_成员。当对象构造完成后,在类成员函数内部可以调用shared_from_this获得该对象自身类型的shared_ptr。千万不要在构造函数里调用share_from_this,因为this还没有完全构造出来,此时无法根据this构造一个正确的weak_ptr。
 

weak_ptr源码

template<class T> class weak_ptr
{
private:

    // Borland 5.5.1 specific workarounds
    typedef weak_ptr<T> this_type;

public:

    typedef typename boost::detail::sp_element< T >::type element_type;

    //pn是weak_count,而不是shared_count,所以weak_ptr不会引起指针引用计数增加。
    weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+
    {
    }

//  generated copy constructor, assignment, destructor are fine...

//如果    定义"BOOST没有右值引用"   为假
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )

// ... except in C++0x, move disables the implicit copy
    //支持copy assignment
    weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
    {
    }

    weak_ptr & operator=( weak_ptr const & r ) BOOST_NOEXCEPT
    {
        px = r.px;
        pn = r.pn;
        return *this;
    }

#endif

//
//  The "obvious(明显的)" converting constructor implementation:
//
//  template<class Y>
//  weak_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws
//  {
//  }
//
//  has a serious problem.
//
//  r.px may already have been invalidated(使无效). The px(r.px)
//  conversion may require(需要) access to *r.px (virtual inheritance).
//
//  It is not possible to avoid spurious(假的,伪造的) access violations since
//  in multithreaded programs r.px may be invalidated at any point.
//

    template<class Y>
#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )

    weak_ptr( weak_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )

#else

    weak_ptr( weak_ptr<Y> const & r )

#endif
    BOOST_NOEXCEPT : px(r.lock().get()), pn(r.pn)
    {
        boost::detail::sp_assert_convertible< Y, T >();
    }

    template<class Y>
    weak_ptr( weak_ptr<Y> && r ) BOOST_NOEXCEPT : px( r.lock().get() ), pn( static_cast< boost::detail::weak_count && >( r.pn ) )  //强转为右值
    {
        boost::detail::sp_assert_convertible< Y, T >();
        r.px = 0;
    }

    // for better efficiency in the T == Y case
    weak_ptr( weak_ptr && r )
    BOOST_NOEXCEPT : px( r.px ), pn( static_cast< boost::detail::weak_count && >( r.pn ) )
    {
        r.px = 0;
    }

    // for better efficiency in the T == Y case
    weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT
    {
        this_type( static_cast< weak_ptr && >( r ) ).swap( *this );
        return *this;
    }

    template<class Y>
    weak_ptr( shared_ptr<Y> const & r )
    BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) //重点weak_ptr的pn=shared_ptr的pn,也就是说weak_count=shared_count
    {
        boost::detail::sp_assert_convertible< Y, T >();
    }

#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)

    template<class Y>
    weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT
    {
        boost::detail::sp_assert_convertible< Y, T >();

        px = r.lock().get();
        pn = r.pn;

        return *this;
    }

#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )

    template<class Y>
    weak_ptr & operator=( weak_ptr<Y> && r ) BOOST_NOEXCEPT
    {
        this_type( static_cast< weak_ptr<Y> && >( r ) ).swap( *this );
        return *this;
    }

#endif

    template<class Y>
    weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT
    {
        boost::detail::sp_assert_convertible< Y, T >();

        px = r.px;
        pn = r.pn;

        return *this;
    }

#endif

    //将weak_ptr提升为shared_ptr,如果已经过期,则返回一个空shared_ptr
    shared_ptr<T> lock() const BOOST_NOEXCEPT   
    {
        return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );   //调用shared_ptr(const weak_ptr<T>& r, sp_nothrow_tag());
    }

    //返回shared_ptr的引用计数,pn是weak_count类型,但是它实际上转调它持有的sp_counted_base指针(和shared_ptr持有同一个)的use_count()函数,所以可以返回所有shared_ptr引用计数的相关信息,下同。
    long use_count() const BOOST_NOEXCEPT
    {
        return pn.use_count();
    }

    //判断shared_ptr是否过期,也就是引用计数是否为0,如果为0,说明shared_ptr已经过期死了,返回true
    bool expired() const BOOST_NOEXCEPT
    {
        return pn.use_count() == 0;
    }

    bool _empty() const // extension, not in std::weak_ptr
    {
        return pn.empty();
    }

    void reset() BOOST_NOEXCEPT // never throws in 1.30+
    {
        this_type().swap(*this);
    }

    void swap(this_type & other) BOOST_NOEXCEPT
    {
        std::swap(px, other.px);
        pn.swap(other.pn);
    }

    template<typename Y>
    void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2)
    {
        px = px2;
        pn = r.pn;
    }

    template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
    {
        return pn < rhs.pn;
    }

    template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
    {
        return pn < rhs.pn;
    }

下面是weak_count的源码:

class weak_count
{
private:

    sp_counted_base * pi_;

    friend class shared_count;

public:

    weak_count(): pi_(0) // nothrow
    {
    }

    weak_count(shared_count const & r): pi_(r.pi_) // nothrow
    {
        if(pi_ != 0) pi_->weak_add_ref();
    }

    weak_count(weak_count const & r): pi_(r.pi_) // nothrow
    {
        if(pi_ != 0) pi_->weak_add_ref();
    }

// Move support

#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
    weak_count(weak_count && r): pi_(r.pi_) // nothrow
    {
        r.pi_ = 0;
    }
#endif

    ~weak_count() // nothrow
    {
        if(pi_ != 0) pi_->weak_release();    //weak_count析构一次,就减少一次sp_count_base的计数!!!!!!
    }

    weak_count & operator= (shared_count const & r) // nothrow
    {
        sp_counted_base * tmp = r.pi_;

        if( tmp != pi_ )
        {
            if(tmp != 0) tmp->weak_add_ref();
            if(pi_ != 0) pi_->weak_release();
            pi_ = tmp;
        }

        return *this;
    }

    weak_count & operator= (weak_count const & r) // nothrow
    {
        sp_counted_base * tmp = r.pi_;

        if( tmp != pi_ )
        {
            if(tmp != 0) tmp->weak_add_ref();
            if(pi_ != 0) pi_->weak_release();
            pi_ = tmp;
        }

        return *this;
    }

    void swap(weak_count & r) // nothrow
    {
        sp_counted_base * tmp = r.pi_;
        r.pi_ = pi_;
        pi_ = tmp;
    }

    long use_count() const // nothrow
    {
        return pi_ != 0? pi_->use_count(): 0;
    }

    bool empty() const // nothrow
    {
        return pi_ == 0;
    }

    friend inline bool operator==(weak_count const & a, weak_count const & b)
    {
        return a.pi_ == b.pi_;
    }

    friend inline bool operator<(weak_count const & a, weak_count const & b)
    {
        return std::less<sp_counted_base *>()(a.pi_, b.pi_);
    }
};

//在这里初始化shared_count中的那两个函数,即利用wakt_count的sp_count_base初始化share_count的sp_count_base,它们是共享的
//这是在调用weak_ptr的lock函数用weak_ptr构造shared_ptr,然后调用本函数的
inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ )
{
    if( pi_ == 0 || !pi_->add_ref_lock() )
    {
        boost::throw_exception( boost::bad_weak_ptr() );
    }
}

inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ )
{
    if( pi_ != 0 && !pi_->add_ref_lock() )
    {
        pi_ = 0;
    }
}

值得注意的是,weak_ptr自身也是引用计数型智能指针,也有引用计数。weak_ptr也支持拷贝分配之类的函数。

上面代码最后的这两个函数是shared_count类的构造函数之一,这是使用weak_ptr的lock函数底层要调用的之一。lock函数是使用weak_ptr构造shared_ptr,这回调用shared_ptr的weak_ptr构造方法,然后shared_ptr的成员shread_count自然也要调用以weak_ptr为参数的构造方法。并且由于lock提升这个操作有多线程并发的可能,所以这里调用的不是sp_counted_base函数的add_ref_copy(该函数是原子的,但功能简单,不能说明提升成功或失败),而是add_ref_lock函数,gcc版本是这样实现的:

inline int atomic_conditional_increment( int * pw )
{
    spinlock_pool<1>::scoped_lock lock( pw );

    int rv = *pw;
    if( rv != 0 ) ++*pw;
    return rv;
}

首先对pw的内存进行上锁,然后再进行相应操作。如果*pw不为0,则weak_ptr提升成功,增加引用计数。如果为0,说明shared_ptr对象已死,不能提升,不增加引用计数,返回0。在shared_count构造函数中(就是上面那个),取消pi_的赋值(不打算指向weak_ptr的sp_counted_base),将它重新赋为空。

如此一来,便可实现weak_ptr提升称为shared_ptr的线程安全了。

C++11中的智能指针unique_ptr、shared_ptr和weak_ptr详解 详细讲解C++11中引入的智能指针unique_ptr、shared_ptr和weak_ptr。 阅读详情

相关推荐

C++ 11 学习总结——智能指针

智能指针 什么是智能指针? 智能指针是借用RAII技术对普通指针进行封装,实质是一个对象,表现为一个指针,即智能的管理动态资源的释放;(重载操作符(->和*)); 对于编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命期即将结束时,智能指针通过析构函数释放有它管理的堆内存。 什么是RAII技术? RAII技术即资源分配及初始化,使用类来封装资源的分配和初始化,再构造函数完成资源的分配和初始化,析构函数完成资源的清理,可以保证正确的初始化和资源释放。 智能指针的作用 del

我不是码农的博客~~~ 691

C++ | shared_ptr与weak_ptr

简单介绍shared_ptr与weak_ptr,仿写系统的shared_ptr与weak_ptr,并解决循环引用的问题.shared_ptr是一种智能指针(smart pointer),作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。 weak_ptr是为配合shared_ptr而引入的一种智能指针。 2.Ref_con 3.shar

大柳_的博客。 5238

c++智能指针weak_ptr源码分析

这个指针比shared_ptr<> 内容少些。

zhangzhangkeji的博客 131

shared_ptr和weak_ptr

程序中需要管理各种各样的资源,为了避免内存泄露,必须确保在资源再也不需要时释放资源,智能指针提供了这一功能。C++标准提供了两大类智能指针,这里主要介绍shared_ptr。多个shared_ptr可以共享同一个资源,并在最后一个拥有资源的shared_ptr被销毁时释放资源。 1、deleter 2、weak_ptr ...

csdn_cjc的博客 2701

《最游记》游戏开发全栈指南:从源码解析到实战部署

本文提供了一份详尽的《最游记》游戏源码全栈开发指南。文章深入解析了这款3D玄幻网游的完整源码结构,涵盖客户端、服务端、引擎和工具链,并提供了从环境搭建、核心模块解析到实战修改与部署的完整流程。对于希望深入理解MMORPG架构的开发者而言,这份指南是宝贵的实战资源。

weixin_28363123的博客 71

CloudCompare横截面工具实战:从点云切片到轮廓提取的完整流程

本文详细介绍了CloudCompare软件中Cross Section工具的核心功能与实战流程。从交互式裁剪框的精准操控,到包络线提取的参数设置与优化,再到内部轮廓提取及批量处理技巧,完整解析了如何从三维点云中高效提取建筑立面、隧道断面等关键轮廓信息,是点云数据处理与分析的实用指南。

weixin_29290963的博客 284

从源码看std::weak_ptr

weak_ptr

leapmotion的博客 748

投研必备工具:Wind(万得)数据库快速入门

Wind数据库对于金融从业者来说是必不可少的一个软件,本文主要介绍了股票和债券的信息查找,帮助后续对数据进行分析,开始学习吧!

weixin_56581108的博客 10万+

shared_ptr & weak_ptr 源码分析

shared_ptr weak_ptr 源码分析,讲解相互构造的过程,记忆引用计数的管理

c553110519的专栏 322

ADS RFpro 射频阻抗仿真步骤

导入器件后,在库里面选取器件的对应模型,如图所示我们选取10pf 系统自带的村田模型。选取网络上的器件,拖入到下面component Models。导入成功后,截取需要仿真的区域(不截取仿真时间会非常长),可以生成对应如下原理图,通过原理图继续调整仿真。图上找到需要仿真链路上的网络,右键设置为信号。的叠层信息,按照PCB板厂提供信息填写完整。选择仿真的频率范围和频点数,生成如下图的RFPro仿真界。,然后再把GND也添加到下面。按图设置截取需要仿真的部分。添加成功后 网络就有了,15 双击run开始仿真。

m0_72954480的博客 3217

在mdk文件移植太多_XCubeClassB代码 的移植

前言ST在www.st.com官网上提供了针对IEC60730/IEC60335 ClassB认证的软件包。软件包分为三个,分别适用STM8,STM32(基于标准外设库)和STM32(基于HAL库):STM8-SafeCLASSB,STM32-CLASSB-SPL,X-CUBE-CLASSB。本文以X-CUBE-CLASSB为例介绍如何做代码的移植以及经常遇到的问题的解决办法。X-CUB...

weixin_28898707的博客 1832

c++11 weak_ptr 源码分析

写在最前。。。 0. 前言 所谓智能指针,可以从字面上理解为“智能”的指针。具体来讲,智能指针和普通指针的用法是相似的,不同之处在于,智能指针可以在适当时机自动释放分配的内存。也就是说,使用智能指针可以很好地避免“忘记释放内存而导致内存泄漏”问题出现。由此可见,C++ 也逐渐开始支持垃圾回收机制了,尽管目前支持程度还有限。 c++11 中发布了shared_ptr、unique_ptr、weak_ptr 用以资源的管理,都是定义在memory 这个头文件中。 std::shared_ptr 允.

私房菜 1753

UG\NX二次开发 获取三平面交点

//如果返回值不为0 则此三个面没交点 int three_faces_point(tag_t tagFace1, tag_t tagFace2, tag_t tagFace3, double *dou_x, double *dou_y, double *dou_z)

王牌飞行员_里海的博客 675

shellmad-24_C++新特性 share_ptr与weak_ptr的源码分析

深入分析shared_ptr与weak_ptr的实现 stl中使用了shared_ptr来管理一个对象的内部指针,并且使用了weak_ptr来防止前面所提到的shared_ptr循环引用的问题。 接下来简单的分析shared_ptr和weak_ptr的实现,最后通过自己写代码来模拟shared_ptr和weak_ptr,达到深入学习的目的: 测试代码如下: #include "stdafx.h" #include <memory> int _tmain(int argc, _TCHAR* ar

esjiang的博客 337

如何做好软件需求分析?

软件需求分析也称为系统需求分析或需求分析工程等,是开发人员经过深入细致的调研和分析,准确理解用户和项目的功能、性能、可靠性等具体要求,将用户非形式的需求表述转化为完整的需求定义,从而确定系统必须做什么的过程。软件开发一般包括:可行性分析、需求分析、软件设计、软件开发、软件测试、软件实施、软件服务等步骤,需求分时软件开发的第一步骤。用户需求分析是指在系统设计之前和设计、开发过程中对用户需求所作的调查与分析,是系统设计、系统完善和系统维护的依据。

qq_41854911的博客 1415

扣子Coze工作流教程:采集公众号爆文,一键仿写自动发布

通过本教程,你学会了如何利用扣子(Coze)平台构建一个完整的公众号文章自动处理工作流。这个系统不仅能够大幅提升内容产出效率,还能通过AI二创保持内容新鲜度和原创性。最佳实践建议:初次使用时,建议先保存为草稿而不是直接发布,以便人工审核;从简单的工作流开始,逐步增加复杂度;定期检查工作流运行日志,优化节点配置。自动化内容创作是新媒体运营的未来趋势,掌握这项技能将使你在数字内容领域占据显著优势。

互联网架构师笔记 1238

C++ 智能指针(shared_ptr/weak_ptr)源码分析

C++11目前已经引入了unique_ptr, shared_ptr, weak_ptr等智能指针以及相关的模板类enable_shared_from_this等。shared_ptr实现了C++中的RAII机制,它不仅仅具有一般指针(build-in/raw)的特性,更重要的是它可以自动管理用户在堆上创建的对象的生命周期,让用户不用为内存回收操心,避免内存泄漏。一般的智能指针都定义为一个模板类,...

gigglesun的专栏 1万+

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

智能指针源码分析(4)——weak_ptr

分析了智能指针weak_ptr源码,并借此完成了自己的weak_ptr版本,需要注意的是对于weak_ptr由于其是shared_ptr的伴随指针,故处处离不开shared_ptr,故代码逻辑很像shared_ptr,写出来的显得有点多。

Tryturned 406

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

C++新特性24_share_ptr与weak_ptr的源码分析(进入源码进行分析,讲的思路清晰但是理解不清楚,以后慢慢研究;“_类名/函数”代表内部的类及方法;)

承接上篇:C++新特性23_weak_ptr的提出及解决循环引用的思路,本篇主要从源码的角度去理解深层次的原理。 1. “Ctrl+左键”进入源代码 2. 智能指针类源代码 shared_ptr 对外提供接口,并无成员变量 表示强指针 : public _Ptr_base weak_ptr 对外提供接口,并无成员变量 表示弱指针 : public _Ptr_base 3. 智能指针指针父类_Ptr_base类源代码 _Ptr_base { 两个成员变量: eleme

分享学习成长历程,Winter is coming! 1007

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

智能指针篇------STL源码分析:shared_ptr 和 weak_ptr、unique_ptr

探究STL中 shared_ptr 和 weak_ptr 源码,分析其各种机制的实现原理:例如 析构动作在创建时捕获、weak_count 的作用、enable_shared_from_this 的实现机制

weixin_44835655的博客 1518

【转载】C++ 智能指针(shared_ptr/weak_ptr)源码分析

发现一篇对C++11智能指针分析很透彻的文章,特转载备忘! 以下转载自:https://blog.youkuaiyun.com/ithiker/article/details/51532484?utm_source=blogxgwz1 C++11目前已经引入了unique_ptr, shared_ptr, weak_ptr等智能指针以及相关的模板类enable_shared_from_this等。s...

weixin_30439131的博客 118

shared_ptr与weak_ptr

本文主要分析了C++中的shared_ptr和weak_ptr智能指针的工作原理及实现机制。shared_ptr采用引用计数管理对象生命周期,支持自定义删除器,但需注意避免循环引用和多指针管理同一裸指针等问题。weak_ptr作为shared_ptr的观察者,不参与引用计数,主要用于解决循环引用和观察对象状态。文章深入剖析了控制块基类sp_count_base的架构,包括引用计数管理、对象释放逻辑等核心机制,并介绍了自定义删除器sp_count_deleter的实现方式。通过源码分析,揭示了智能指针如何通过

m0_47175840的博客 818

C++智能指针(scoped_ptr<T> 、shared_ptr<T> 、weak_ptr<T> )

从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr 、shared_ptr 、weak_ptr 源码分析)

a19576的专栏 542

GNU C++ 智能指针26- 解析__weak_ptr类2

目录 一、关键点解析 1、expired() 2、expired与lock的线程安全性 3、use_count() 和 expired() 函数 二、源码分析 一、关键点解析 1、expired() bool expired() const noexcept { return _M_refcount._M_get_use_count() == 0; } 2、expired与lock的线程安全性 (1)expired不是线程安全的 ...

kupePoem的专栏 832
上一篇: shared_ptr源码分析后续
下一篇: 为什么多线程读写shared_ptr需要加锁
FreeeLinux
博客等级 码龄11年 421粉丝 356原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值