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

http://hi.baidu.com/cpuramdisk/item/7c2f8d77385e0f29d7a89cf0

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如果希望被继承,析构函数就应该为虚函数)。

时间: 2024-10-24 23:37:01

[转] shared_from_this 几个值得注意的地方的相关文章

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

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

6 个回答 赞同89反对,不会显示你的姓名 唐元鹏,扯淡爱好者 Jc droid.李明亮.知乎用户 等人赞同 作为一个android菜鸟开发者,代码水平不咋样,却练就了一身上传app的本领,大体说一下我的经验.上传每个市场也许会布局不同,但内容大致一样,图标.apk.文字介绍.关键词.截图准备好了,基本每个市场都可以上传.认领每个市场的具体需要的东西有所不同,但是如果有代码截图.公司营业执照(个人的话应该是身份证).app的安装包,基本上都能认领成功,再和客服联系一下妥妥的.审核规则安卓市场:审

java里的一些特别值得注意的地方

return 语句的作用:1.返回值 2.结束某个方法的执行. 局部变量必需要初始化,全局变量系统会默认初始值: 整型数赋默认值为0. 浮点数赋默认值为0.0,boolean赋默认值为false. char型赋默认值为'\u0000'. 复杂类型赋默认值为null. 栈是执行时的单位.而堆是存储的单位 栈:自己主动分配连续的空间,后进先出,放置局部变量 堆:不连续.放置new出来的变量 堆里面还有方法区,类的代码信息.static变量,常量池(字符串常量等) public class Anima

Heroku在第三方服务接入上,值得借鉴的地方

近期为了准备开发私有云,研究了heroku第三方服务的接入.这里总结下heroku在这一方面的亮点. 一.强大的接入工具 要把自己的服务集成到heroku上,你要和heroku定协议,按照协议开发,然后验证,最后还要发布到heroku.这个过程会很耗时,而heroku提供了一个叫kensa的命令行工具,能减轻不少工作量,特别是其中的测试功能,能够逐步验证接入的相关约定,相当方便,回想自己之前的项目,需要做机器接入,很多都是人工验证,相当原始落后.不过,如果能提供图形界面,我觉得会更加上流. 二.

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

Android上有很多输入法应用,每种输入法都有各自的特点,输入法多数时候是和EditText配合使用,结合我自己的亲身实践分享一下使用EditText过程中遇到的一些问题及解决方法. 设置默认输入法   有时候为了提高用户体验,在弹出输入法时需要设置默认的输入状态,比如单词应用弹出输入法时,输入法最好是在英文输入状态下.如果是字典应用,弹出输入法时最好是在中文输入状态下,Android并没有提供设置默认的输入状态的接口,但我们可以通过如下方法一样能够达到想要的效果:   默认中文: mEdit

C#多态--真不知道为啥起这么高大上的名,我想应该说--C#中有一些值得注意的地方

先看两个函数 void test(int i); void test(string str); 这就是多态 using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { test(); test(1); test("1&quo

android开发之网络棋牌类在线游戏开发心得(服务器端、Java) 好文章值得收藏

标签: android服务器 2013-10-09 17:28 3618人阅读 评论(0) 收藏 举报 分类: android(11) 转自:http://blog.csdn.net/bromon/article/details/253330 Bromon原创 请尊重版权 一个多人在线的棋牌类网络游戏的项目临近尾声,我参与了该项目的整个设计流程,并且完成了90%的核心代码.关于这个项目,有很多地方值得聊一聊.本系列不打算把这个项目将得多么详细规范,那是设计文档应该描述的,我打算只说说一些值得注意

RequireJS使用注意地方

使用RequireJS做异步模块加载,有几点值得注意的地方: 1.模块定义两种写法 1. 存在依赖的函数式定义 如果模块存在依赖:则第一个参数是依赖的名称数组:第二个参数是函数,在模块的所有依赖加载完毕后,该函数会被调用来定义该模块,因此该模块应该返回一个定义了本模块的object.依赖关系会以参数的形式注入到该函数上,参数列表与依赖名称列表一一对应. define(['a'], function(aJ) { var hello = function(){ aJ.hello('i am c.js

开发:随笔记录之 OSGI的jar添加几个小问题及其注意的地方

在引用jar包的时候,如果是项目中引用的包,则需要在MANIFEST.MF 里面定义 一.外部jar: 比如:外部包引用需要在Import package里面 定义一下,如:google-gson-2.2.2.jar   我需要引用这个外部包的话, 需要在Import package 里面加入一行:com.google.gson;version="2.2.2",   这里有个值得注意的地方,如下(这里是网上搜集的,具体我没实践): BundleA: import-package: or