2016-11-02: boost::enable_shared_from_this
使用场景
当类对象被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 来生成一个了。
参考资料
what is the usefulness of enable_shared_from_this
2016-11-02: boost::enable_shared_from_this的更多相关文章
- sicily 1007. To and Fro 2016 11 02
// Problem#: 1007// Submission#: 4893204// The source code is licensed under Creative Commons Attrib ...
- 1036. Crypto Columns 2016 11 02
/* 对于题目多读几遍,然后再关键字排序的时候,把对应的数组序号也排序, EYDE MBLR THAN MEKT ETOE EOTH MEETME B ...
- 【读书笔记】2016.11.19 北航 《GDG 谷歌开发者大会》整理
2016.11.19 周六,我们在 北航参加了<GDG 谷歌开发者大会>,在web专场,聆听了谷歌公司的与会专家的技术分享. 中午免费的午餐,下午精美的下午茶,还有精湛的技术,都是我们队谷 ...
- star ccm+ 11.02安装
STAR CCM+是CD-Adapco公司的主打软件,其安装方式较为简单,这里以图文方式详细描述STAR CCM+11.02安装过程. 1 安装准备工作2 正式安装3 软件破解4 软件测试 1 安装准 ...
- 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 ...
- 微信iphone7、 ios10播放视频解决方案 2016.11.10
2016.11.10日更新以下方法 微信最新出同层播放规范 即使是官方的也无法解决所有android手机的问题. 另外iphone 5 .5s 某些手机始终会弹出播放,请继续采用 “以下是老的解决办法 ...
- 最新的 cocoapods 安装与使用(2016.11)
cocoapods简介: cocoapods 是iOS的类库管理工具,可以让开发者很方便集成各种第三方库,而不用去网站上一个个下载,再一个个文件夹的拖进项目中,还得添加相关的系统依赖库.只需要安装好c ...
- 【转载】webstorm11(注册,激活,破解,码,一起支持正版,最新可用)(2016.11.16更新)
很多人都发现 http://idea.lanyus.com/ 不能激活了 很多帖子说的 http://15.idea.lanyus.com/ 之类都用不了了 最近封的厉害仅作测试 选择 License ...
- 比特币源码分析--C++11和boost库的应用
比特币源码分析--C++11和boost库的应用 我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...
随机推荐
- 【P1825】表达式整除
又自己写出来了好开心OvO 原题: 24点这个游戏好多人都玩过,就是给你4个数,添加相应的运算符,是否可以得到结果是24.小x在玩了很多遍这个游戏之后,想把这个游戏给改变一下.给你n个整数,在n个整数 ...
- 学习笔记-Java编程思想
2016-01-03 Swith(整数选择因子):必须是int或char这样的整数值. Java中不包含goto语句,但是可以通过标识符实现类似的控制.
- python命令行解释器 argparse
一: argparse介绍 1. argparse argparse,它是Python标准库中推荐使用的编写命令行程序的工具 parser = argparse.ArgumentParser() ...
- C# 创建开机启动核心代码
#region 访问 AppSettings private void SaveAppSetting(string key, string value) { var config = Configur ...
- winform上控件太多,绘制时会逐个出现,通常说双缓冲能解决但实际不能解决的问题的解决方法。
protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle ...
- UISegmentedControl和UIStepper的使用
UISegmentedControl:分栏控件,常用的属性和方法是 1.tintColor:控制分栏控件的颜色风格 2.insertSegmentWithTitle(Image):插入分栏标题(图片) ...
- [2016.01.01]万峰文本处理专家 v2.0
<万峰文本处理专家>是一款简单易用,且功能强大的各类文本文件处理软件.1.支持多任务的处理模式,允许一次处理多个任务.2.支持正则表达式替换,替换更加强大:3.支持各类关键字的行处理操作: ...
- SPI总线协议及SPI时序图详解
SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚 ...
- VirtualBox后台运行虚拟机(无图形界面启动虚拟机)
有时候可能会用虚拟机搭建集群,这是通常希望不现实图形界面,试了半天,似乎只有Virtual Box支持无图形界面运行虚拟机,方法如下: 在Virtual Box的安装目录中找到VBoxManage,M ...
- vim中执行shell命令
1):!command 不退出vim,并执行shell命令command,将命令输出显示在vim的命令区域,不会改变当前编辑的文件的内容 例如 :!ls -l 特别的可以运行:!bas ...