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
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
浙公网安备 33010602011771号