东阳的学习笔记
shared_from_this()是C++多线程编程
中经常会使用的到的一种方法。
问题提出:
见 linux 多线程服务器编程 P23. 如果 StockFactory 的生命期
比 Stock 短,那么下列语句就会 core dump
// ...
pStock.reset(new Stock(key),
boost::bind(&StockFactory::deleteStock,
this,
_1));
// ...
为了解决这个问题,我们似乎应该祭出惯用的 shared_ptr
大法, 问题来了:
如何获得一个指向当前对象的 shared_ptr 呢?
shared_from_this
enable_shared_from_this是一个类,将有上述需求的类继承自它,就可以解决上面所提出的问题。
enable_shared_from_this 有一个私有成员变量,保存了一个 weak_ptr
指针, 可以看到其保存的就是 this
。
我们只需要将问题中的代码修改为下面的就可以解决问题了:
- 继承 enable_shared_from_this
- 在bind中使用
class StockFactory : public boost::enable_shared_from_this<StockFactory>,
boost::noncopyable
{ /* ... */ }
pStock.reset(new Stock(key),
boost::bind(&StockFactory::deleteStock,
shared_from_this(),
_1));
我们先来看看源码:
template<class T> class enable_shared_from_this
{
protected:
BOOST_CONSTEXPR enable_shared_from_this() BOOST_SP_NOEXCEPT{}
BOOST_CONSTEXPR enable_shared_from_this(enable_shared_from_this const &) BOOST_SP_NOEXCEPT{}
enable_shared_from_this & operator=(enable_shared_from_this const &) BOOST_SP_NOEXCEPT { return *this; }
// ~weak_ptr<T> newer throws, so this call also must not throw
~enable_shared_from_this() BOOST_SP_NOEXCEPT{}
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;
}
weak_ptr<T> weak_from_this() BOOST_SP_NOEXCEPT
{
return weak_this_;
}
weak_ptr<T const> weak_from_this() const BOOST_SP_NOEXCEPT
{
return weak_this_;
}
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 BOOST_SP_NOEXCEPT
{
if( weak_this_.expired() )
{
weak_this_ = shared_ptr<T>( *ppx, py );
}
}
private:
mutable weak_ptr<T> weak_this_;
};
但是,StockFactory的生命期似乎被意外延长了
,不小于boost::function对象
弱回调
有时候我们需要“如果对象还活着,就调用它的成员函数,否则忽略之的语义”。
弱回调使用示例。(Factory通常是个 singleton,在程序正常运行期间不会销毁,这是只是为了展示弱回调的用法)
pStock.reset(new Stock(key),
boost::bind(&StockFactory::weakDeleteCallback,
boost::weak_ptr<StockFactory>(shared_from_this()),
_1));
// 上面必须把 shared_from_this() 转型为 weak_ptr, 才不会延长生命期
// 因为 bind 绑定的是实参类型而不是形参类型
// ...
static void weakDeleteCallback(const boost::weak_ptr<StockFactory>& wkFactory, Stock *stock)
{
shared_ptr<StockFactory> factory(wkFactory.lock()); // 尝试提升
if (factory) // 如果 factory 还在,那就清理stocks_
{
factory->removeStock(stock);
}
delete stock; // sorry, i lied
}