zoukankan      html  css  js  c++  java
  • c++11 enable_shared_from_this

    本质的原因:raw data和引用计数的管理块,可能是分开的

    使用场景: 需要在对象中得到shared ptr, 

    错误的代码:直接构造新的shared_ptr<A>对象,两个shared_ptr objects 是独立的,pointer to the same raw mem. 两个独立的managed objects. 因此会导致undefined behaviour, delete raw data twice, 通常会导致crash.

    class A {
    public:
        std::shared_ptr<A> getShared() {
            return std::shared_ptr<A>(this);
        }
    };
    int main() {
        std::shared_ptr<A> pa = std::make_shared<A>();
        std::shared_ptr<A> pbad = pa->getShared();
        return 0;
    }

    具体场景: 为什么一定要在类的成员函数里面得到this的shared_ptr呢?直接去裸指针this为什么不行?在异步IO的编程中,callback函数通常在另外的线程中调用,跟主线程是分离开的,这是就涉及到一个对象生存期lifetime的概念,

    //blocking GetRawData is trivial since it is done in child thread 
    std::future<RedisRuslt> RedisConnector::AsyncSetDagToRedis(const SBOString&key, PDAG dag, CDBMEnv* env)
    {
    	assert(dag != nullptr);
    	//start one thread to do the heavy setDagToRedis op
    	PDAG tmpDag;
    	dag->Duplicate(&tmpDag, dbmKeepData);
    	std::shared_ptr<DAG> smartDag(tmpDag);
    	return std::async(std::bind(&RedisConnector::AsyncSetSmartDagToRedis, shared_from_this(),key, smartDag, env));}
    }  

    分析:如果redisconnector对象在async函数调用之前就析构了,那么另外线程中调用bind函数时候,this指针就会失效。因此用shared_from_this(),*this对象生存期得到延长.

     boost库的example,是shared_from_this()典型的场景 https://www.boost.org/doc/libs/1_39_0/doc/html/boost_asio/tutorial/tutdaytime3/src.html  

    实现原理:利用weak ptr作为桥梁,在需要shared_ptr时,通过weak_ptr构造出临时的shared_ptr对象

    那么weak_ptr何时初始化呢?为什么时候指向shared_ptr呢,显然需要被shared_ptr管理的类对象需要基础一个enable_shared_from_this<T>的基类,基类中有weak_ptr这个class member,初始化的时机,应该在shared_ptr<A>(new A())的时候.

    由此引申出引用的错误案例:

    class D:public boost::enable_shared_from_this<D>
    {
    public:
        D()
        {
            boost::shared_ptr<D> p=shared_from_this();
        }
        void func()
        {
            boost::shared_ptr<D> p=shared_from_this();
        }
        
    };
    int main(){
       D num;
       num.func();
    }

    从上面可以得到,enable_shared_from_this 的成员 weakthis 不是在 enable_shared_from_this 的构造函数中初始化的,而是通过 _internal_accept_owner 来赋初值的。而这个函数是 shared_ptr 在初始化的时候调用的。得出结论:不要在构造函数中使用 shared_from_this.

    如果有多重继承的情况,而且不同的父类都继承了 boost::enable_shared_from_this,则会出现比较怪异的情况,多重继承在 C++ 中原本就是不推荐的,所以应该在应用中尽量避免这种情况。

    源码:

    template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn( p ) // Y must be complete
    {
        boost::detail::sp_enable_shared_from_this( this, p, p );
    }
    
    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 )
        {
          //调用 enable_shared_from_this对象的函数  
          pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
        }
    }
    
    
    namespace boost
    {
    
    template<class T> class enable_shared_from_this
    {
    protected:
    
        enable_shared_from_this()
        {
        }
    
        enable_shared_from_this(enable_shared_from_this const &)
        {
        }
    
        enable_shared_from_this & operator=(enable_shared_from_this const &)
        {
            return *this;
        }
    
        ~enable_shared_from_this()
        {
        }
    
    public:
    
        shared_ptr<T> shared_from_this()
        {
            shared_ptr<T> p( weak_this_ );
            BOOST_ASSERT( p.get() == this );
            return p;
        }
    
        shared_ptr<T const> shared_from_this() const
        {
            shared_ptr<T const> p( weak_this_ );
            BOOST_ASSERT( p.get() == this );
            return p;
        }
    
    public: // actually private, but avoids compiler template friendship issues
    
        // Note: invoked automatically by shared_ptr; do not call
        template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
        {
            if( weak_this_.expired() )
            {
               //shared_ptr通过拷贝构造一个临时的shared_ptr,然后赋值给weak_ptr 
               weak_this_ = shared_ptr<T>( *ppx, py );
            }
        }
    
    private:
    
        mutable weak_ptr<T> weak_this_;
    };
    
    } // namespace boost
    
    #endif  // #ifndef BOOST_SMART_PTR_ENABLE_SHARED_FROM_THIS_HPP_INCLUDED
    

    A common implementation for enable_shared_from_this is to hold a weak reference (such as std::weak_ptr) to this. The constructors of std::shared_ptr detect the presence of an enable_shared_from_this base and assign the newly created 

     参考链接:

    https://www.cnblogs.com/codingmengmeng/p/9123874.html

    https://github.com/prehistoric-penguin/blog-post/blob/master/2015-05-22-implementation-enable_shared_from_this.md

    http://www.gaccob.com/publish/2013-08-11-boost-smart-ptr.html

    https://blog.csdn.net/ithiker/article/details/51532484

    https://www.cnblogs.com/lzjsky/archive/2011/05/05/2037363.html

  • 相关阅读:
    根据不同运行环境配置和组织node.js应用
    python下pip使用bug汇总
    python的虚拟环境
    nginx使用手册--nginx的命令行参数
    nginx使用手册--nginx.conf文件配置详解
    使用async读取异步数据
    [Bootstrap]组件(三)
    [Bootstrap]组件(二)
    [Bootstrap]组件(一)
    [javascript|基本概念|一元操作符]学习笔记
  • 原文地址:https://www.cnblogs.com/kkshaq/p/10430364.html
Copyright © 2011-2022 走看看