本质的原因: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
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