zoukankan      html  css  js  c++  java
  • [转] 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如果希望被继承,析构函数就应该为虚函数)。

  • 相关阅读:
    哈工大中文篇章关系语料
    MongoDB学习笔记~关于官方驱动集成IQueryable之后的一些事
    MongoDB学习笔记~为IMongoRepository接口更新指定字段
    MongoDB学习笔记系列
    MongoDB学习笔记~为IMongoRepository接口添加了增删改方法,针对官方驱动
    MongoDB学习笔记~为IMongoRepository接口添加了排序和表达式树,针对官方驱动
    Android NDK入门实例 计算斐波那契数列二生成.so库文件
    Spring Autowire自动装配
    在gem5的full system下运行 alpha编译的测试程序 running gem5 on ubuntu in full system mode in alpha
    工厂三兄弟之抽象工厂模式(二)
  • 原文地址:https://www.cnblogs.com/qiangxia/p/4288341.html
Copyright © 2011-2022 走看看