shared_from_this()是enable_shared_from_this<T>的成员 函数,返回shared_ptr<T>。首先需要注意的是,这个函数仅在shared_ptr<T>的构造函数被调用之后才能使 用。原因是enable_shared_from_this::weak_ptr并不在构造函数中设置,而是在shared_ptr<T>的 构造函数中设置。

如下代码是错误的:

  1. class D:public boost::enable_shared_from_this<D>
  2. {
  3. public:
  4. D()
  5. {
  6. boost::shared_ptr<D> p=shared_from_this();
  7. }
  8. };

复制代码

原 因很简单,在D的构造函数中虽然可以保证enable_shared_from_this<D>的构造函数已经被调用,但正如前面所 说,weak_ptr还没有设置。

如下代码也是错误的:

  1. class D:public boost::enable_shared_from_this<D>
  2. {
  3. public:
  4. void func()
  5. {
  6. boost::shared_ptr<D> p=shared_from_this();
  7. }
  8. };
  9. void main()
  10. {
  11. D d;
  12. d.func();
  13. }

复制代码

错 误原因同上。

如下代码是正确的:

  1. void main()
  2. {
  3. boost::shared_ptr<D> d(new D);
  4. d->func();
  5. }

复制代码

这 里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>。例如如下代码是错误的:

  1. class A:public boost::enable_shared_from_this<A>
  2. {
  3. public:
  4. A():a(1){}
  5. virtual ~A(){}
  6. boost::shared_ptr<A> get_ptra(){return shared_from_this();}
  7. int a;
  8. };
  9. class B:public A,public boost::enable_shared_from_this<B>
  10. {
  11. public:
  12. B():b(2){}
  13. boost::shared_ptr<B> get_ptrb()
  14. {
  15. return boost::enable_shared_from_this<B>::shared_from_this();
  16. }
  17. int b;
  18. };
  19. int _tmain(int argc, _TCHAR* argv[])
  20. {
  21. {
  22. boost::shared_ptr<B> x(new B);
  23. boost::shared_ptr<A> a1 = x->get_ptra();
  24. boost::shared_ptr<B> b1 = x->get_ptrb();
  25. }
  26. return 0;
  27. }

复制代码

注 意上面代码中,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的构造函数:

  1. template<class Y>
  2. explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
  3. {
  4. boost::detail::sp_enable_shared_from_this( pn, p, p );
  5. }
  6. 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 )
  7. {
  8. if(pe != 0) pe->_internal_weak_this._internal_assign(const_cast<Y*>(px), pn);
  9. }

复制代码

注 意这个sp_enable_shared_from_this是一个模板函数,而且仅调用了一次,所以不可能2个 enable_shared_from_this基类的weak_ptr都被赋值。但问题在于,在调换了B的定义之后结果居然是不一样的。这里有一个很隐 秘的编译器BUG。按道理来说,编译器在编译这段代码时,应该注意到无法真正决断该怎么实例化sp_enable_shared_from_this并且 报一个错,但vc 2008并没有报错,而是通过编译了。(g++会在此处报错)

那么正确的解法是怎样的呢?

  1. class B:public A
  2. {
  3. public:
  4. B():b(2){}
  5. boost::shared_ptr<B> get_ptrb()
  6. {
  7. return boost::dynamic_pointer_cast<B>(shared_from_this());
  8. }
  9. int b;
  10. };

复制代码

注 意到这里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 几个值得注意的地方的更多相关文章

  1. [转] shared_from_this 几个值得注意的地方

    http://hi.baidu.com/cpuramdisk/item/7c2f8d77385e0f29d7a89cf0 shared_from_this()是enable_shared_from_t ...

  2. 關於Validform 控件 值得注意的地方

    Validform控件其實用起來挺方便的,直接百度就能找到官網,有直接的demo做參考.這些我就不提了,我所要說的是關於Validform控件的ajax的提交. Validform中有個參數ajaxP ...

  3. MSDN值得学习的地方

    作者:朱金灿 来源:http://blog.csdn.net/clever101 我一直认为:如果你没有乔布斯那样的天才,能够从头脑中原创出好产品,那么最好先学习分析好的产品,它到底好在哪里?哪些地方 ...

  4. golang 值得注意的地方(2则)

    golang 的语法和使用方式都非常简单明了,没有花哨的语法糖,也没有多余的关键字. 但是即使是这么简洁的语言,仍然有一些不那么直白,需要注意的地方,比如下面2点. interface 赋值 nil ...

  5. 国内各大安卓(Android)市场的上传方式、认领、通过审核有哪些不同,有什么值得注意的地方?

    6 个回答 赞同89反对,不会显示你的姓名 唐元鹏,扯淡爱好者 Jc droid.李明亮.知乎用户 等人赞同 作为一个android菜鸟开发者,代码水平不咋样,却练就了一身上传app的本领,大体说一下 ...

  6. SQL指令中一些特别值得注意的地方

    SQL基本指令要频繁使用,要是理解错了,将来工作一定会出现很大的麻烦.今天再重新梳理一下基本的SQL语法 SQL指令 in: 这个指令,我曾经发生过把它和python中的in搞混的错误.python中 ...

  7. Android EditText的使用及值得注意的地方

    Android上有很多输入法应用,每种输入法都有各自的特点,输入法多数时候是和EditText配合使用,结合我自己的亲身实践分享一下使用EditText过程中遇到的一些问题及解决方法. 设置默认输入法 ...

  8. Android笔记(三):View一些值得注意的地方

    Button android:textAllCaps="false" // Button上的英文字符不转成大写 EditText android:maxLines="2& ...

  9. 关于div+css布局值得注意的地方

    注意项 我们知道,如果想要两个 div(即块级元素)挨着一起排列,可以将其设置为inline-block(行内-块元素). 不过要注意两个div内的内容的对齐方式将是垂直中间对齐,所以这时候就需要使用 ...

随机推荐

  1. su Authentication failure解决

    su Authentication failure解决 关于Ubuntu桌面系统su root时认证失败的问题 1. Ubuntu 默认没有给root用户设置密码,当我们su root命令时, 提示认 ...

  2. java项目打jar包

    首先 在工程中,右键项目,有个export,选择JAR File,就能导出jar包. 一.java项目没有导入第三方jar包 1. 首先在Eclipse中打开项目, 右键点击项目,选择“Export” ...

  3. 寻找所有javaee官方文档的方法

    所有跟java有关的首先要去oracle官网. 所有文档都放在: Oracle Technology Network 即:著名的OTN网站 链接在首页的最后一个标签: 侧面就是documentions ...

  4. android—资源文件(res)的引用

    android项目中res目录下的文件含义各不相同主要有两种方式引用它们 例子:在string.xml中定义一个<string name="hello">Hello W ...

  5. BZOJ 2819: Nim( nim + DFS序 + 树状数组 + LCA )

    虽然vfleaking好像想卡DFS...但我还是用DFS过了... 路径上的石堆异或和=0就是必败, 否则就是必胜(nim游戏). 这样就变成一个经典问题了, 用DFS序+BIT+LCA就可以在O( ...

  6. 收集的jquery插件

    1.精美jQuery分页插件 带滑动条分页使用HTML5实现刮刮卡效果 今天开始我们来收集一些jQuery分页插件,今天第一款jQuery分页插件适用于长翻页列表的分页应用,因为这款分页插件带有滑动条 ...

  7. css如此强大你知道吗

    看个这个大神纯 CSS 绘制<辛普森一家>人物头像我惊呆了,css如此牛x <div id="wrap"> <div class="cont ...

  8. windows 下面的内存泄漏排查.

    内存泄漏排查 一下本人只是简单的介绍一个实用, 如果读者很感兴趣, 可以查阅msdn自己去深入调查相关的API和原理. API 介绍 1. 马上打印泄漏信息:_CrtDumpMemoryLeaks() ...

  9. xmu1214: 购物

    1214: 购物 Time Limit: 500 MS  Memory Limit: 64 MBSubmit: 10  Solved: 5[Submit][Status][Web Board] Des ...

  10. HTML5API___geolocation

    地理位置查询:geolocation window.navigator.geolocation 该对象下总共有3个方法 Geolocation {getCurrentPosition: functio ...