zoukankan      html  css  js  c++  java
  • 2016-11-02: boost::enable_shared_from_this

    使用场景

        当类对象被shared_ptr管理时,需要在类自己定义的函数中把当前对象作为参数传递给其他函数时,必须传递一个shared_ptr,否则就不能保持shared_ptr管理这个类对象的语义。因为有一个raw pointer指向这个类对象,而shared_ptr对类对象的这个引用没有计数,很可能shared_ptr已经把类对象资源释放了,而那个调用函数还在使用类对象--显然,这肯定会产生错误。

    使用方法

        在上述场景中,我们需要在类内部获得自己的shared_ptr。我们可以让自己定义的类继承boost::enable_shared_from_this。因为,boost中的enable_shared_from_this类提供了一个shared_frome_this()成员函数可以让子类内部获得自身的shared_ptr对象,满足类实现过程中需要传递自身shared_ptr的使用需求。

    注意事项

        虽然enable_shared_from_this是基类,但它却是在shared_ptr里面初始化enable_shared_from_this的成员weak_ptr。因此不能在子类的构造方法里面调用shared_from_this(),因为这个时候weak_ptr还是空值。

        为什么在类的内部不直接使用this指针,因为我们程序中用shared_ptr来管理指针,如果我们在类的内部传递的过程中用原始指针,这样类内部的引用shared_ptr不会察觉到,因为有可能我们传进去的时候已经被shared_ptr释放掉了。

    实现原理

    限制条件

        在类对象本身当中不能存储类对象本身的 shared_ptr,否则类对象 shared_ptr 的引用计数永远也不会为0了,从而资源永远不会释放,除非程序结束。
        类对象肯定是外部函数通过某种机制分配的,而且一经分配立即交给 shared_ptr 管理(再次强调一遍:给 shared_ptr 管理的资源必须在分配时交给 shared_ptr),而且以后凡是需要共享使用类对象的地方必须使用这个 shared_ptr 当作右值来构造产生或者拷贝产生另一个 shared_ptr 从而达到共享使用的目的。(即you must never create more than one shared_ptr from the same raw pointer

    可能方案

        有了以上两点的限制,要实现我们的目标(即在类对象内部使用类对象的 shared_ptr)有以下两种方案:
    1、类对象的外部 shared_ptr 作为函数参数传给类的需要引用类对象自身的函数——显然,这种方法很丑陋,而且并不是所有的情况都可行(如在外部 shared_ptr 不可见的作用域中就不行);
    2、类对象自身存储某种信息,在需要自身 shared_ptr 时来产生一个临时的 shared_ptr 。
    显然,第2种方法更优雅(对于用户来说),关键是信息怎么存储?
    对了, weak_ptr !
    实际上, boost 中就是这样实现的。

    实现过程

    但现在的问题是:何时初始化这个 weak_ptr ?因为类对象生成时还没有生成相应的用来管理这个对象的 shared_ptr 。
    boost 1.39.0 中是这样实现的:
    首先生成类 A :会依次调用 enable_shared_from_this 的构造函数(定义为 protected),以及类 A 的构造函数。在调用 enable_shared_from_this 的构造函数时,会初始化定义在 enable_shared_from_this 中的 weak_ptr (调用其默认构造函数),这时这个 weak_ptr 是无效的(或者说不指向任何对象)。
    接着:外部程序会把指向类 A 对象的指针作为初始化参数来初始化一个 shared_ptr 。
    现在来看看 shared_ptr 是如何初始化的,shared_ptr 定义了如下构造函数:
    template<class Y>
        explicit shared_ptr( Y * p ): px( p ), pn( p )
        {
            boost::detail::sp_enable_shared_from_this( this, p, p );
        }
    里面调用了 boost::detail::sp_enable_shared_from_this :
    template< class X, class Y, class T >
    inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx,
    Y const * py, boost::enable_shared_from_this< T > const * pe )
    {
        if( pe != 0 )
        {
            pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
        }
    }
    里面又调用了 enable_shared_from_this 的 _internal_accept_owner :
    template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
        {
            if( weak_this_.expired() )
            {
                weak_this_ = shared_ptr<T>( *ppx, py );
            }
        }
    而在这里对 enable_shared_from_this 的成员 weak_ptr 进行拷贝赋值,使得整个 weak_ptr 作为类对象 shared_ptr 的一个观察者。
    这时,当类对象本身需要自身的 shared_ptr 时,就可以从这个 weak_ptr 来生成一个了。

    参考资料

    enable_from_this方法的使用与陷阱

    what is the usefulness of enable_shared_from_this

    Weak Pointers

  • 相关阅读:
    TimelineJS JSON 数据格式
    FFMS2 API 译文 [原创]
    用 Delphi 7 实现基于 FFMS2 的视频转 GIF 工具 [原创]
    FFMS2 官方说明译文 [原创]
    华为悦盒 EC6108V9U 破解过程全记录(root扫盲) [原创]
    Delphi 中的 RectTracker
    Delphi 7中对StretchBlt, StretchDIBits, DrawDibDraw, BitBlt 的性能测试
    【最后一篇API译文】Android开发-API指南- Contacts Provider
    Android开发-API指南- Calendar Provider
    Android开发-API指南-数据存储
  • 原文地址:https://www.cnblogs.com/zhouLee/p/6023109.html
Copyright © 2011-2022 走看看