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如果希望被继承,析构函数就应该为虚函数)。
Shared_from_this 几个值得注意的地方的更多相关文章
- [转] shared_from_this 几个值得注意的地方
http://hi.baidu.com/cpuramdisk/item/7c2f8d77385e0f29d7a89cf0 shared_from_this()是enable_shared_from_t ...
- 關於Validform 控件 值得注意的地方
Validform控件其實用起來挺方便的,直接百度就能找到官網,有直接的demo做參考.這些我就不提了,我所要說的是關於Validform控件的ajax的提交. Validform中有個參數ajaxP ...
- MSDN值得学习的地方
作者:朱金灿 来源:http://blog.csdn.net/clever101 我一直认为:如果你没有乔布斯那样的天才,能够从头脑中原创出好产品,那么最好先学习分析好的产品,它到底好在哪里?哪些地方 ...
- golang 值得注意的地方(2则)
golang 的语法和使用方式都非常简单明了,没有花哨的语法糖,也没有多余的关键字. 但是即使是这么简洁的语言,仍然有一些不那么直白,需要注意的地方,比如下面2点. interface 赋值 nil ...
- 国内各大安卓(Android)市场的上传方式、认领、通过审核有哪些不同,有什么值得注意的地方?
6 个回答 赞同89反对,不会显示你的姓名 唐元鹏,扯淡爱好者 Jc droid.李明亮.知乎用户 等人赞同 作为一个android菜鸟开发者,代码水平不咋样,却练就了一身上传app的本领,大体说一下 ...
- SQL指令中一些特别值得注意的地方
SQL基本指令要频繁使用,要是理解错了,将来工作一定会出现很大的麻烦.今天再重新梳理一下基本的SQL语法 SQL指令 in: 这个指令,我曾经发生过把它和python中的in搞混的错误.python中 ...
- Android EditText的使用及值得注意的地方
Android上有很多输入法应用,每种输入法都有各自的特点,输入法多数时候是和EditText配合使用,结合我自己的亲身实践分享一下使用EditText过程中遇到的一些问题及解决方法. 设置默认输入法 ...
- Android笔记(三):View一些值得注意的地方
Button android:textAllCaps="false" // Button上的英文字符不转成大写 EditText android:maxLines="2& ...
- 关于div+css布局值得注意的地方
注意项 我们知道,如果想要两个 div(即块级元素)挨着一起排列,可以将其设置为inline-block(行内-块元素). 不过要注意两个div内的内容的对齐方式将是垂直中间对齐,所以这时候就需要使用 ...
随机推荐
- 在 Visio 中录制宏
在“开发工具”选项卡上,单击“录制宏”.(如果您看不到“开发工具”选项卡,请参阅下面的“显示‘开发工具’选项卡”.) 在“宏名”框中,键入宏名称. 在“快捷键”框中,键入与 Ctrl 键一起使用可运行 ...
- SQL2008 'OFFSET' 附近有语法错误。 在 FETCH 语句中选项 NEXT 的用法无效。
'OFFSET' 附近有语法错误.在 FETCH 语句中选项 NEXT 的用法无效. 说明: 执行当前 Web 请求期间,出现未经处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出 ...
- JS 代码调试经验总结(菜鸟必读)
前言:不知不觉写了很多,希望你能耐心看完这篇文章 任何一个编程者都少不了要去调试代码,不管你是高手还是菜鸟,调试程序都是一项必不可少的工作.一般来说调试程序是在编写代码之后或测试期修改Bug 时进行的 ...
- MySQL 5.7 重置root默认密码
http://www.cnblogs.com/jym-sunshine/p/5314101.html mysql5.7.11修改root默认密码 知道 MySQL 出了5.7了,并且网上说性能提高 ...
- jsf小例子
有人问我用过jsf没? 当时没有用过,就看了一下: 写了一个小例子 JSF和struts2 差不多的,都有一些配置和跳转 struts2的action配置和JSF的faces-config.xm ...
- 百度apistore第三方登陆
最近做一个个人博客,其中的登陆模块我想使用第三方登陆来做.上网搜一下有好多例子,但是大多数都是一个网站的第三方登陆,如QQ.微博.人人,没有集成的组件,于是就在网上搜一下百度的apistore,百度果 ...
- 容易被误解的overflow:hidden
http://www.ofcss.com/2011/03/20/misunderstood-of-overflow-hidden.html(转) 容易被误解的overflow:hidden 15条评论 ...
- 转 SSH框架搭建详细图文教程
原址:http://blog.sina.com.cn/s/blog_a6a6b3cd01017c57.html 什么是SSH? SSH对应 struts spring hibernatestruts ...
- c# winform读取xml创建菜单
动态创建菜单使得程序灵活性大大增加,本文根据读取xml文件中的配置菜单项来动态创建菜单,代码如下: using System; using System.Collections.Generic; us ...
- 也许有用(也谈VC中ModifyStyle&ModifyStyleEx无法改变控件的Style)
一个View中用到了一个CListCtrl,在OnInitialUpdate函数里面他调用了m_listCtrl.ModifyStyleEx(0, LVS_EX_FULLROWSELECT);但是结 ...