boost智能指针源代码分析

2014年4月17日 由 Creater 留言 »

首先来看shared_ptr.h

inline void _sp_set_shared_from_this( ... )
{
}
template<typename T> inline void _sp_set_shared_from_this(shared_ptr<T>* sp, enable_shared_from_this<T>* p)
{
	if (p)
	{
		p->_internal_accept_owner( *sp );
	}
}

这里对_sp_set_shared_from_this函数进行了重载,目的就是区分shared_ptr<>管理的对象是否继承自enable_shared_from_this.

class classA
{

};

class classB : enable_shared_from_this<classB>
{

};

当定义为shared_ptr<classA> 时则调用的是第一个函数,当定义为shared_ptr<classB>时则调用第二个函数。

那么什么时候调用_sp_set_shared_from_this呢?第二个函数的作用是什么呢?

1.先来看什么时候调用

shared_ptr(T * p = NULL)
	{
		m_ptr = p;
		m_count = new sp_counted_base(1,1);
		_sp_set_shared_from_this(this, m_ptr);
	}

	shared_ptr(const weak_ptr<T>& right)
	{
		m_ptr = right.get();
		m_count = right._get_sp();
		addref();
		_sp_set_shared_from_this(this, m_ptr);
	}

	shared_ptr(const this_type& o)
	{
		m_ptr = o.m_ptr;
		m_count = o.m_count;
		addref();
		_sp_set_shared_from_this(this, m_ptr);
	}

不只是上边的构造函数,赋值与复制操作符都会调用。具体的调用_sp_set_shared_from_this哪个重载版本函数,就是依靠m_ptr来推断。

2._sp_set_shared_from_this函数有什么用呢?

由前面的说明,已经知道能够调用_sp_set_shared_from_this实际有操作的类都是从enable_shared_from_this继承而来,在其内部实际上委托给了enable_shared_from_this基类

p->_internal_accept_owner( *sp );

这个函数的作用,实际上就是初始化了weak_ptr智能指针,先列出enable_shared_from_this这个类

template<typename T>
class enable_shared_from_this
{
public:
	shared_ptr<T> shared_from_this()
	{
		return shared_ptr<T>( weak_this_ );
	}
public:
	void _internal_accept_owner(const shared_ptr<T>& p)
	{
		weak_this_ = p;
	}
private:
	weak_ptr<T> weak_this_;
};

weak_ptr智能指针weak_this_的作用就是对shared_ptr进行观测,来看是怎么观测,由上边的_internal_accept_owner函数可以看出,实际上有如下的构造

	weak_ptr(const shared_ptr<T>& right)
	{
		m_ptr = right.get();
		m_count = shared_ptr<T>::_get_counted(right);
		m_count->weak.inc();
	}

这里可以看出weak_ptr智能指针,仅仅增加了观测,而没有对shared_ptr的计数器做任何修改。

综上,sp_set_shared_from_this函数就是为保存T对象的智能指针shared_ptr<T>增加观测智能指针weak_ptr<T>,并初始化。也说明了weak_ptr是依靠shared_ptr而成立的。

3.来看为什么上说有的类继承自enable_shared_from_this,为什么要继承自他呢?

继承自他的原因是想使用enable_shared_from_this的以下成员函数,继承他就可以让this变身为shared_ptr

	shared_ptr<T> shared_from_this()
	{
		return shared_ptr<T>( weak_this_ );
	}

来看下面的例子

class classC {
public:
    classC(): x_(4) {
        cout << "classC::classC()" << endl;
    }

    ~classC() {
        cout << "classC::~classC()" << endl;
    }

    void f() {
        shared_ptr<classC> p(this);
        cout << p->x_ << endl;
    }

private:
    int x_;
};

int main(int argc, char** argv) {
    shared_ptr<classC> x(new classC);
    x->f();
    return 0;
}

这段代码,将会两次析构 ,结果是灾难性的。甚至有的函数传入thsi指针后会被不小心delete,导致悬垂指针。

但是,我们将上边的部分代码修改成以下的

    void f() {
        shared_ptr<classC> p = shared_from_this();
        cout << p->x_ << endl;
    }

这样就正确了,这里演示的比较简单,在boost中,使用function,bind等的时候更容易出错。

4.weak_ptr如何使用

weak_ptr 不控制对象的生命期,但是它知道对象是否还活着。如果对象还活着,那么它可以提升 为有效的 shared_ptr;如果对象已经死了,提升会失败,返回一个空的 shared_ptr。此行为是线程安全的 。要想使用waek_ptr观测的智能指针share_ptr,必须使用以下的函数

	shared_ptr<T> lock() const
	{
		if ( !expired() )
		{
			return shared_ptr<T>(*this);
		}
		return shared_ptr<T>(NULL);
	}

对观测的shared_ptr增加一个引用计数,然后返回shared_ptr,这样就不会出现多次释放或者悬垂指针了。

广告位

评论已关闭.