智能指針源碼分析(4)——weak_ptr

上一篇:https://blog.csdn.net/qq_41345173/article/details/104279991

1.簡介

weak_ptr是爲了配合shared_ptr而引入的一種智能指針,因爲它不具有普通指針的行爲,沒有重載operator*和->,它的最大作用在於協助shared_ptr工作,像旁觀者那樣觀測資源的使用情況。值得一提的是它可以解決循環引用的問題,下面先貼一個來自http://www.cplusplus.com/reference/網站的weak_ptr的例子熟悉一下他的具體用法:

// weak_ptr::lock example
#include <iostream>
#include <memory>

int main () {
  std::shared_ptr<int> sp1,sp2;
  std::weak_ptr<int> wp;
                                       // sharing group:
                                       // --------------
  sp1 = std::make_shared<int> (20);    // sp1
  wp = sp1;                            // sp1, wp

  sp2 = wp.lock();                     // sp1, wp, sp2
  sp1.reset();                         //      wp, sp2

  sp1 = wp.lock();                     // sp1, wp, sp2

  std::cout << "*sp1: " << *sp1 << '\n';
  std::cout << "*sp2: " << *sp2 << '\n';

  return 0;
}

Output:
*sp1: 20
*sp2: 20

2.weak_ptr源碼分析

template<class T> class weak_ptr
{
private:
    typedef weak_ptr<T> this_type;
    template<class Y> friend class weak_ptr;    //友元類的聲明
    template<class Y> friend class shared_ptr;

    element_type * px;            // contained pointer
    boost::detail::weak_count pn; // reference counter
public:

    typedef typename boost::detail::sp_element< T >::type element_type;
    weak_ptr() BOOST_NOEXCEPT : px(0), pn() {}//無參構造

    //拷貝構造
    weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn ){}
    weak_ptr & operator=( weak_ptr const & r ) //重載賦值運算符
    ...
    /*省略各種構造函數及相關賦值運算符的重載*/
    shared_ptr<T> lock() const BOOST_NOEXCEPT{
        return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );//若維護的shared_ptr的引用計數不爲0則返回,否則爲null
    }

    long use_count() const BOOST_NOEXCEPT{
        return pn.use_count();
    }

    bool expired() const //看是否失效
    {
        return pn.use_count() == 0;
    }

    bool _empty() const // 判空
    {
        return pn.empty();
    }

    void reset() BOOST_NOEXCEPT // never throws in 1.30+
    {
        this_type().swap(*this);
    }

    void swap(this_type & other) BOOST_NOEXCEPT
    {
        std::swap(px, other.px);
        pn.swap(other.pn);
    }

    template<typename Y>
    void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2)
    {
        px = px2;
        pn = r.pn;
    }

    template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
    {
        return pn < rhs.pn;
    }

    template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT
    {
        return pn < rhs.pn;
    }
};  // weak_ptr

上面各種說明已經非常清楚,主要是weak_count類,來瞅一瞅與shared_count的區別:

class weak_count
{
private:
    sp_counted_base * pi_;

觀其私有成員可以看出其和shared_count必定是一樣的套路,不過由於其爲伴隨指針,則直接接受淺拷貝即可,相對應該會簡單不少,而由其源碼我們也可以發現確實如此:

 template<class Y>weak_ptr( shared_ptr<Y> const & r ):px( r.px ), pn( r.pn ){}

3.描繪自己的weak_ptr

#include <iostream>
#include <memory>
#include <string>

using namespace std;
template<class T> class weak_ptr;
template<class T> class shared_ptr;

class sp_counted_base
{
private:
    sp_counted_base( sp_counted_base const & );
    sp_counted_base & operator= ( sp_counted_base const & );
    long use_count_;        // #shared
public:
    sp_counted_base(): use_count_( 1 ){}//該類唯一構造函數
    virtual ~sp_counted_base(){
    	cout<<"sp_counted_base destroy ..."<<endl;
    }
    virtual void dispose() = 0;
    void release() {
    	if(--use_count_==0)
    	{
			dispose();
		}
    }
    long use_count() const // nothrow
    {
        return static_cast<long>( use_count_ );
    }
    void add_ref_copy()
    {
        ++use_count_;
    }
};

template<class X> class sp_counted_impl_p: public sp_counted_base
{
private:
    X * px_;
public:
    explicit sp_counted_impl_p( X * px ): px_( px ){}
    virtual ~sp_counted_impl_p(){
    	cout<<"sp_counted_impl_p destroy ..."<<endl;
    }
    void dispose(){
    	delete px_;
    	delete this;
    }
};
class weak_count;
class shared_count
{
private:
	friend class weak_count;
    sp_counted_base *pi_;
public:
    template <class Y>
    shared_count(Y *p):pi_(new sp_counted_impl_p<Y>(p)){}
    shared_count(shared_count const& r):pi_(r.pi_){
    	pi_->add_ref_copy();
    }
    explicit shared_count(weak_count const& r);
    ~shared_count(){
        if(pi_!=0)
            pi_->release();
        cout<<"destroy shared_count..."<<endl;
    }
    long use_count(){
		return pi_!=0?pi_->use_count():0;
	}
};
class weak_count
{
private:
	friend class shared_count;
    sp_counted_base * pi_; 
public:
	weak_count(shared_count const &r):pi_(r.pi_){}
	~weak_count(){}
	weak_count(weak_count const& r):pi_(r.pi_){}
	long use_count(){
		return pi_!=0?pi_->use_count():0;
	}
	void swap(weak_count & r){
		sp_counted_base *tmp = r.pi_;
		r.pi_ = pi_;
		pi_ = tmp;
	}
};
    shared_count::shared_count(weak_count const& r):pi_(r.pi_){
    	pi_->add_ref_copy();
    }
template<class T> class shared_ptr
{
public:
    T *px;
    shared_count pn;
    template<class Y> friend class weak_ptr;    //友元類的聲明
public:
    shared_ptr(T *p):px(p),pn(p){}
    shared_ptr(weak_ptr<T> const &r):px(r.px),pn(r.pn){}
    ~shared_ptr(){
        cout<<"destroy shared_array..."<<endl;
    }
    T & operator*()const{
        return *px;
    }
    long use_count(){
        return pn.use_count();
    }
};

template<class T> class weak_ptr
{
private:
	template<class Y> friend class weak_ptr;    //友元類的聲明
    template<class Y> friend class shared_ptr;

    typedef weak_ptr<T> this_type;
    T * px;                 
    weak_count  pn;    // reference counter
public:
    weak_ptr(shared_ptr<T> const &pt)  :px(pt.px),pn(pt.pn){}
    ~weak_ptr(){
    	cout<<"weak_ptr destroy ..."<<endl;
    }
    T & operator*()const{
        return *px;
    }
    long use_count(){
        return pn.use_count();
    }
    shared_ptr<T> lock()const{
    	if(px)
    		return shared_ptr<T>(*this);
    }
};

int main () {
  shared_ptr<string> foo (new string("Hello World!"));
  weak_ptr<string>bar(foo);
  cout << "foo and bar\n" ;
  cout<<"foo_str: "<<*foo<<";  bar_str: "<<*bar<<endl;
  cout<<"foo_use_count: "<<foo.use_count()<<";	bar_use_count: "<<bar.use_count()<<endl;
  shared_ptr<string>pa(bar.lock());
  cout<<"foo_use_count: "<<foo.use_count()<<";	pa_use_count: "<<pa.use_count()<<endl;
  return 0;
}

output:
foo and bar
foo_str: Hello World!; bar_str: Hello World!
foo_use_count: 1; bar_use_count: 1
foo_use_count: 2; pa_use_count: 2
destroy shared_array…
destroy shared_count…
weak_ptr destroy …
destroy shared_array…
sp_counted_impl_p destroy …
sp_counted_base destroy …
destroy shared_count…
顯然,weak_ptr其本身並不是太複雜,代碼之所以這麼長是由於還包括對shared_ptr的構造,因爲離開了shared_ptr的weak_ptr就沒什麼存在的意義了,這就是weak_ptr,至此,智能指針剖析之路可以告一段落了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章