Shared_from_this 几个值得注意的地方
shared_from_this()是enable_shared_from_this<T>的成员 函数,返回shared_ptr<T>。首先需要注意的是,这个函数仅在shared_ptr<T>的构造函数被调用之后才能使 用。原因是enable_shared_from_this::weak_ptr并不在构造函数中设置,而是在shared_ptr<T>的 构造函数中设置。
如下代码是错误的:
- class D:public boost::enable_shared_from_this<D>
- {
- public:
- D()
- {
- boost::shared_ptr<D> p=shared_from_this();
- }
- };
复制代码
原 因很简单,在D的构造函数中虽然可以保证enable_shared_from_this<D>的构造函数已经被调用,但正如前面所 说,weak_ptr还没有设置。
如下代码也是错误的:
- class D:public boost::enable_shared_from_this<D>
- {
- public:
- void func()
- {
- boost::shared_ptr<D> p=shared_from_this();
- }
- };
- void main()
- {
- D d;
- d.func();
- }
复制代码
错 误原因同上。
如下代码是正确的:
- void main()
- {
- boost::shared_ptr<D> d(new D);
- d->func();
- }
复制代码
这 里boost::shared_ptr<D> d(new D)实际上执行了3个动作:首先调用enable_shared_from_this<D>的构造函数;其次调用D的构造函数;最后调用 shared_ptr<D>的构造函数。是第3个动作设置了enable_shared_from_this<D>的 weak_ptr,而不是第1个动作。这个地方是很违背c++常理和逻辑的,必须小心。
结论是,不要在构造函数中使用shared_from_this;其次,如果要使用shared_ptr,则应该 在所有地方均使用,不能使用D d这种方式,也决不要传递裸指针。
另一个值得注意的地方是在类的继承树中不能有2个或更多个enable_shared_from_this<T>。例如如下代码是错误的:
- class A:public boost::enable_shared_from_this<A>
- {
- public:
- A():a(1){}
- virtual ~A(){}
- boost::shared_ptr<A> get_ptra(){return shared_from_this();}
- int a;
- };
- class B:public A,public boost::enable_shared_from_this<B>
- {
- public:
- B():b(2){}
- boost::shared_ptr<B> get_ptrb()
- {
- return boost::enable_shared_from_this<B>::shared_from_this();
- }
- int b;
- };
- int _tmain(int argc, _TCHAR* argv[])
- {
- {
- boost::shared_ptr<B> x(new B);
- boost::shared_ptr<A> a1 = x->get_ptra();
- boost::shared_ptr<B> b1 = x->get_ptrb();
- }
- return 0;
- }
复制代码
注 意上面代码中,B同时拥有2个enable_shared_from_this的基类,一个是 enable_shared_from_this<A>,另一个是enable_shared_from_this<B>。在 boost::shared_ptr<B> x(new B);这行代码中,shared_ptr<B>的构造函数仅会设置2个基类中的一个的weak_ptr。在上面的例子中,仅设置 enable_shared_from_this<A>的。如果修改B的定义为:
class B:public boost::enable_shared_from_this<B>,public A,
则仅设置enable_shared_from_this<B>的weak_ptr。很明显都是错误的。
那么enable_shared_from_this以及shared_ptr为何要如此实现呢?又为什么会有如此怪异的结果呢?
首先考察shared_ptr的构造函数:
- template<class Y>
- explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
- {
- boost::detail::sp_enable_shared_from_this( pn, p, p );
- }
- template<class T, class Y> void sp_enable_shared_from_this( shared_count const & pn, boost::enable_shared_from_this<T> const * pe, Y const * px )
- {
- if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
- }
复制代码
注 意这个sp_enable_shared_from_this是一个模板函数,而且仅调用了一次,所以不可能2个 enable_shared_from_this基类的weak_ptr都被赋值。但问题在于,在调换了B的定义之后结果居然是不一样的。这里有一个很隐 秘的编译器BUG。按道理来说,编译器在编译这段代码时,应该注意到无法真正决断该怎么实例化sp_enable_shared_from_this并且 报一个错,但vc 2008并没有报错,而是通过编译了。(g++会在此处报错)
那么正确的解法是怎样的呢?
- class B:public A
- {
- public:
- B():b(2){}
- boost::shared_ptr<B> get_ptrb()
- {
- return boost::dynamic_pointer_cast<B>(shared_from_this());
- }
- int b;
- };
复制代码
注 意到这里B并没有直接继承enable_shared_from_this,而是使用dynamic_pointer_cast进行了类型转换。
关于为什么enable_shared_from_this是这样实现的,可以参看作者原文:
Every enable_shared_from_this base contains a weak_ptr, The shared_ptr constructor looks up the enable_shared_from_this base and initializes its weak_ptr accordingly. This doesn't work when there are
two or more enable_shared_from_this bases, though.
I could put the weak_ptr in a virtual polymorphic base. This would force polymorphism on all clients of enable_shared_from_this... probably acceptable. It will also force a dynamic_pointer_cast in every
shared_from_this, and this may be harder to swallow, particularly in cases where RTTI is off. So I'm not sure.
If you do want the above behavior, it's easy to duplicate, as I already responded in my first post on the topic. Just make FooB return dynamic_pointer_cast<B>( FooA() ) and remove the enable_shared_from_this<B>
base (A needs to be made polymorphic, of course).
注意为了让dynamic_pointer_cast能工作,A必须具有虚函数,那么最简单的做法当然是令其析构函 数为虚函数(通常一个class如果希望被继承,析构函数就应该为虚函数)。
转载于:https://www.cnblogs.com/rooney/archive/2013/03/31/2992101.html
Shared_from_this 几个值得注意的地方相关推荐
- axios拦截器_78.1K 的 Axios 项目有哪些值得借鉴的地方
Axios 是一个基于 Promise 的 HTTP 客户端,同时支持浏览器和 Node.js 环境.它是一个优秀的 HTTP 客户端,被广泛地应用在大量的 Web 项目中. 由上图可知,Axios ...
- 关于Socket和IOCP的一些值得注意的地方
关于Socket和IOCP的一些值得注意的地方 IOCP是一整套高性能的IO操作异步模型,可以用在文件操作也可以用在网络SOCKET操作上面.当用在网络SOCKET上时,在服务器端主要配合Aceept ...
- 任何人都有值得学习的地方,横瓜向[水牛党](4618415)请教问题
虽然不知道水牛党是谁,但任何人都有值得学习的地方.做人就要多学习. 横瓜(601069289)22:13:32 大神有什么指教? 横瓜(601069289)22:13:38 [水牛党]?(461841 ...
- Kotlin 1.4 和未来值得期待的地方
对于企业来说,目前的Android开发面临着许多挑战,尤其是选择哪种技术用于开发最好的Android应用程序. Kotlin和Java是用于Android应用程序开发的两种编程语言,即使是有技术背景的 ...
- 任何值得去的地方,都没有捷径。
任何值得去的地方,都没有捷径:任何值得等待的人,都会迟来一些: 任何值得追逐的梦想,都必须在一路艰辛中备受嘲笑. 所以,不要怕,不要担心你所追逐的有可能是错的. 因为,不被嘲笑的梦想不是梦想. The ...
- 华为p50预计售价鸿蒙是什么,华为P50没赶上首发鸿蒙系统,还有哪些值得期待的地方?...
摘要:按照以往惯例,华为P系列新机会在4月发布,华为P50系列首发预装鸿蒙OS也是顺理成章的事.然而,令人意外的是,由于华为P50系列的发布延期,首发内置搭载鸿蒙系统的手机竟然不是华为最新旗舰P50系 ...
- MSDN值得学习的地方
作者:朱金灿 来源:http://blog.csdn.net/clever101 我一直认为:如果你没有乔布斯那样的天才,能够从头脑中原创出好产品,那么最好先学习分析好的产品,它到底好在哪里?哪些地方 ...
- [分享] 网页设计者值得一去的地方
一.网页设计类 ------------------------------- 1.网站名称:蓝色理想 网站地址: http://www.blueidea.com/ 简介: 哈哈,这个不用说了. -- ...
- 网页设计者值得一去的地方
蓝色转过来的,还没看,先留着,慢慢看! 一.网页设计类 ------------------------------- 1.网站名称:蓝色理想 网站地址: http://www.blueidea.co ...
最新文章
- JSP显示页面和数据库乱码
- 每个人的宿命都是从文本走向二进制,你也不例外 !
- 太赞了!开源下载机器学习经典书 PRML所有相关资料:中文译本,官方代码,课程视频,学习笔记...
- Mysql捕捉(网站)应用执行的语句
- 不能错过的RTS经典:《蘑菇战争2》是如何做玩法创新的?
- 怎样验证TextBox输入的全是数字 - .NET技术 / ASP.NET
- SAP UI5 初学者教程之二十 - SAP UI5 的表达式绑定用法讲解
- Android应用程序之间共享文字和图片(一)
- linux ppp漏洞,Linux下ppp拨号的实现(Arm)
- 爬虫找工作要掌握什么_找爬虫工作必须掌握scrapy框架究竟什么?
- python必背入门代码-初学Python必背手册
- XP中轻松获取未使用的IP地址
- 08 Python 文件和数据格式化
- 算法【打渔晒网问题】
- 动态给div背景图片赋值
- centos环境:Do not run Composer as root/super user的解决办法。
- 用定时器T0查询方式P0口8位控制LED闪烁
- Android 7.1 车机 下载 Android 系统 在线升级,将安装包放到/data/下进行升级
- 简洁易用的记账小程序——微点记账
- 20220321 东航MU5735航班事故应急监测