使用场景

当类对象被shared_ptr管理时,需要在类自己定义的函数中把当前对象作为参数传递给其他函数时,必须传递一个shared_ptr,否则就不能保持shared_ptr管理这个类对象的语义。因为有一个raw pointer指向这个类对象,而shared_ptr对类对象的这个引用没有计数,很可能shared_ptr已经把类对象资源释放了,而那个调用函数还在使用类对象--显然,这肯定会产生错误。

使用方法

在上述场景中,我们需要在类内部获得自己的shared_ptr。我们可以让自己定义的类继承boost::enable_shared_from_this。因为,boost中的enable_shared_from_this类提供了一个shared_frome_this()成员函数可以让子类内部获得自身的shared_ptr对象,满足类实现过程中需要传递自身shared_ptr的使用需求。

注意事项

虽然enable_shared_from_this是基类,但它却是在shared_ptr里面初始化enable_shared_from_this的成员weak_ptr。因此不能在子类的构造方法里面调用shared_from_this(),因为这个时候weak_ptr还是空值。

为什么在类的内部不直接使用this指针,因为我们程序中用shared_ptr来管理指针,如果我们在类的内部传递的过程中用原始指针,这样类内部的引用shared_ptr不会察觉到,因为有可能我们传进去的时候已经被shared_ptr释放掉了。

实现原理

限制条件

在类对象本身当中不能存储类对象本身的 shared_ptr,否则类对象 shared_ptr 的引用计数永远也不会为0了,从而资源永远不会释放,除非程序结束。
    类对象肯定是外部函数通过某种机制分配的,而且一经分配立即交给 shared_ptr 管理(再次强调一遍:给 shared_ptr 管理的资源必须在分配时交给 shared_ptr),而且以后凡是需要共享使用类对象的地方必须使用这个 shared_ptr 当作右值来构造产生或者拷贝产生另一个 shared_ptr 从而达到共享使用的目的。(即you must never create more than one shared_ptr from the same raw pointer

可能方案

有了以上两点的限制,要实现我们的目标(即在类对象内部使用类对象的 shared_ptr)有以下两种方案:
1、类对象的外部 shared_ptr 作为函数参数传给类的需要引用类对象自身的函数——显然,这种方法很丑陋,而且并不是所有的情况都可行(如在外部 shared_ptr 不可见的作用域中就不行);
2、类对象自身存储某种信息,在需要自身 shared_ptr 时来产生一个临时的 shared_ptr 。
显然,第2种方法更优雅(对于用户来说),关键是信息怎么存储?
对了, weak_ptr !
实际上, boost 中就是这样实现的。

实现过程

但现在的问题是:何时初始化这个 weak_ptr ?因为类对象生成时还没有生成相应的用来管理这个对象的 shared_ptr 。
boost 1.39.0 中是这样实现的:
首先生成类 A :会依次调用 enable_shared_from_this 的构造函数(定义为 protected),以及类 A 的构造函数。在调用 enable_shared_from_this 的构造函数时,会初始化定义在 enable_shared_from_this 中的 weak_ptr (调用其默认构造函数),这时这个 weak_ptr 是无效的(或者说不指向任何对象)。
接着:外部程序会把指向类 A 对象的指针作为初始化参数来初始化一个 shared_ptr 。
现在来看看 shared_ptr 是如何初始化的,shared_ptr 定义了如下构造函数:
template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn( p )
    {
        boost::detail::sp_enable_shared_from_this( this, p, p );
    }
里面调用了 boost::detail::sp_enable_shared_from_this :
template< class X, class Y, class T >
inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx,
Y const * py, boost::enable_shared_from_this< T > const * pe )
{
    if( pe != 0 )
    {
        pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
    }
}
里面又调用了 enable_shared_from_this 的 _internal_accept_owner :
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
    {
        if( weak_this_.expired() )
        {
            weak_this_ = shared_ptr<T>( *ppx, py );
        }
    }
而在这里对 enable_shared_from_this 的成员 weak_ptr 进行拷贝赋值,使得整个 weak_ptr 作为类对象 shared_ptr 的一个观察者。
这时,当类对象本身需要自身的 shared_ptr 时,就可以从这个 weak_ptr 来生成一个了。

参考资料

enable_from_this方法的使用与陷阱

what is the usefulness of enable_shared_from_this

Weak Pointers

2016-11-02: boost::enable_shared_from_this的更多相关文章

  1. sicily 1007. To and Fro 2016 11 02

    // Problem#: 1007// Submission#: 4893204// The source code is licensed under Creative Commons Attrib ...

  2. 1036. Crypto Columns 2016 11 02

    /* 对于题目多读几遍,然后再关键字排序的时候,把对应的数组序号也排序, EYDE    MBLR    THAN    MEKT    ETOE    EOTH        MEETME    B ...

  3. 【读书笔记】2016.11.19 北航 《GDG 谷歌开发者大会》整理

    2016.11.19 周六,我们在 北航参加了<GDG 谷歌开发者大会>,在web专场,聆听了谷歌公司的与会专家的技术分享. 中午免费的午餐,下午精美的下午茶,还有精湛的技术,都是我们队谷 ...

  4. star ccm+ 11.02安装

    STAR CCM+是CD-Adapco公司的主打软件,其安装方式较为简单,这里以图文方式详细描述STAR CCM+11.02安装过程. 1 安装准备工作2 正式安装3 软件破解4 软件测试 1 安装准 ...

  5. U3D笔记11:47 2016/11/30-15:15 2016/12/19

    11:47 2016/11/30Before you can load a level you have to add it to the list of levels used in the gam ...

  6. 微信iphone7、 ios10播放视频解决方案 2016.11.10

    2016.11.10日更新以下方法 微信最新出同层播放规范 即使是官方的也无法解决所有android手机的问题. 另外iphone 5 .5s 某些手机始终会弹出播放,请继续采用 “以下是老的解决办法 ...

  7. 最新的 cocoapods 安装与使用(2016.11)

    cocoapods简介: cocoapods 是iOS的类库管理工具,可以让开发者很方便集成各种第三方库,而不用去网站上一个个下载,再一个个文件夹的拖进项目中,还得添加相关的系统依赖库.只需要安装好c ...

  8. 【转载】webstorm11(注册,激活,破解,码,一起支持正版,最新可用)(2016.11.16更新)

    很多人都发现 http://idea.lanyus.com/ 不能激活了 很多帖子说的 http://15.idea.lanyus.com/ 之类都用不了了 最近封的厉害仅作测试 选择 License ...

  9. 比特币源码分析--C++11和boost库的应用

    比特币源码分析--C++11和boost库的应用     我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...

随机推荐

  1. 实验1_IPv6地址配置

    IPv6地址配置 实验任务 (1)掌握如何在路由器及PC上配置IPv6地址 (2)掌握如何用IPv6 ping命令进行IPv6地址可达性检查 (3)掌握如何用命令来查看IPv6地址配置 实验过程 在R ...

  2. 关于位图读取函数int Load_Bitmap_File的lseek问题。

    事情是这样的,本人在编译3D游戏编程大师技巧中的程序是遇到了一个关于位图读取函数int Load_Bitmap_File的lseek问题. 我使用以下位图读取函数读取位图事报错如下: int Load ...

  3. online_jf.lua --累计在线时间领取物品(积分)的lua脚本

    原作者: ayase 8-27修正 修复首次使用后的红字不需要额外进数据库导入计分表,这lua全自动生成 ----------------------------------------------- ...

  4. JAVA语言的本质优势

    虽然Java应用最广泛,但与其它语言比并没有什么技术上的优势.常会看到各种抱怨,说Java语言设计不如C#,对native的精确控制和灵活性不然C++,动态性.开发效率方便不如Ruby,Python, ...

  5. unity, Shader.Find的一个坑

    所以对于没有被任何东西引用,只靠在游戏运行时使用Shader.Find换上去的shader,为了双保险,可以首先放到resources文件夹里,另外,再在ProjectSettings->Gra ...

  6. 【转】怎么让VS2015编写的程序在XP中顺利运行

    1. 概述 默认配置下VS2015编写的应用程序只能在Win8/Win10上运行.但幸好还保留了生成XP程序的设置项.XP和Win2003的用户还是大量存在的,我们程序软件的发布不能不考虑他们.另外X ...

  7. Fatal error 829---数据库 ID 8,页 (1:80740) 已标记为 RestorePending,可能表明磁盘已损坏(日志备份和热备、双机的重要性)

    问题现象: 在业务数据库中查询:SELECT a.NAME FROM SYSOBJECTS a WHERE a.NAME LIKE '%2015' AND a.XTYPE='u' 提示:消息 21,级 ...

  8. MapWinGIS.ocx 注册

    (1)不管对版本4.8还是4.9.3,运行环境都必须为32位的.Net Frame 3.5,低了高了都不行,会导致注册OCX失败. (2)对于MapWinGIS.ocx 4.8 版本,需要32位的 M ...

  9. zabbix3.0安装之图形界面显示异常【server】

    前面记录过Zabbix3.0的安装过程,遇到一些坑,当时就在博文最后提到过,显示界面只有文字没有样式的问题.今天就解决这个小问题. 首先, 我们的安装是基于nginx作为web服务器的,不是传统的用A ...

  10. ecstore-lnmp环境下crontab不执行原因

    因为lnmp.org默认禁止了proc_open函数,需要开启 开启后 lnmp restart ==== contab还是用crontab -e好,有些用www用户的似乎执行不了