shared_ptr,weak_ptr源碼解析

下面的代碼是我在看了ubuntu16.04系統默認自帶的stl源碼後整理的shared_ptr和weak_ptr代碼簡潔版,爲了容易理解去掉了一些基類,函數以及對多線程等情況的處理,對變量名和函數名也做了修改。

// counted_ptr只能通過new在堆上構造,而不在棧上構造。
template<typename Ptr>
class counted_ptr {
    public:
        explicit counted_ptr(Ptr p):ptr(p), use_count(1), weak_count(1) {}

        // 資源的釋放由函數dispose負責,所以析構函數不需要任何操作
        ~counted_ptr() {}

        // 增加計數(use_count)
        void add_ref_copy() {++use_count;}

        // 從weak_ptr轉化爲shared_ptr時候需要調用,
        // 因爲weak_ptr並不會增加計數(use_count),
        // 所以weak_ptr指向的資源可能已經被釋放
        void add_ref_lock() { 
            if(use_count == 0)
                THROW_BAD_WEAK_PTR;
            ++use_count;
        }   

        // 每增加一個weak_ptr,weak_count計數加一
        void weak_add_ref() {++weak_count;}

        // 當weak_count爲0的時候,說明既不存在shared_ptr也不存在weak_ptr
        // 對象在管理ptr指向的資源,所以該計數對象(*this)也可以釋放了
        // (ptr指向的資源在最後一個shared_ptr對象析構的時候已經被釋放了)。
        void weak_release() {
            if(--weak_count == 0)
                destroy();
        }
        int get_use_count() const {return use_count;}
        void dispose() {delete ptr;} //(use_count)計數變爲0,釋放掉所管理的資源
        void destroy() {delete this;} // 釋放計數對象本身(會調用析構函數)

        // 每個shared_ptr對象析構的時候都要調用該函數
        // 在最後一個shared_ptr對象析構時(use_count變爲0)釋放ptr指向的資源
        // 如果weak_count也變爲0,說明也不存在weak_ptr對象了,所以計數對象本身也可以釋放了
        void relase() {
            if(--use_count == 0) {
                dispose();
                if(--weak_count == 0)
                    destroy();
            }
        }
    private:
        // 禁止複製
        counted_ptr(const counted_ptr&) = delete;
        counted_ptr& operator=(const counted_ptr&) = delete;

        int use_count; // 負責管理ptr指向資源的shared_ptr對象的個數

        // 還在使用該計數對象(*this,而不是ptr指向的資源)的weak_ptr對象個數,如果至
        // 少存在一個也在使用該count_ptr對象則再加1。如果weak_count變爲0,則說明既沒有
        // weak_ptr也不沒有shared_ptr在使用該計數對象,則可以釋放掉該計數對象;如果
        // use_count=0而weak_count!=0則ptr指向的資源已被釋放,但還存在weak_ptr在使用
        // 該計數對象,所以還不能釋放該計數對象。
        int weak_count; 
        Ptr ptr;
};
// 向前聲明,所以可以在shared_count內使用weak_count
template <typename Ptr> class weak_count;

template <typename Ptr>
class shared_count {
    public:
        constexpr shared_count(): pi(0) {}
        explicit shared_count(Ptr p): pi(0) {
            try {
                pi = new counted_ptr<Ptr>(p);
            }
            catch(...) {
                delete p;
                throw;
            }
        }
        shared_count(const shared_count& r): pi(r.pi) {
            if(pi != 0)
                pi->add_ref_copy();
        }
        // 由weak_ptr得到shared_ptr,需要檢查所管理的資源釋放已經被釋放,
        // 如果沒有被釋放,則增加計數
        shared_count(const weak_count& r): pi(r.pi) {
            if(pi != nullptr)
                pi->add_ref_lock(); 
        }
        shared_count& operator=(const shared_count& r) {
            counted_ptr<Ptr> tmp = r.pi;
            if(tmp != pi) {
                if(tmp != 0)
                    tmp->add_ref_copy(); // 增加r所管理的資源的計數
                if(pi != 0)
                    pi->release(); // 使原來資源的計數減一,如果減一後變爲0還需要釋放掉資源
                pi = tmp;
            }
            return *this;
        }
        ~shared_count() {
            if(pi != nullptr)
                pi->release();
        }
        void swap(shared_count& r) {
            counted_ptr<Ptr>* tmp = r.pi;
            r.pi = pi;
            pi = tmp;
        }
        int get_use_count() const {
            return pi != 0 ? pi->get_use_count() : 0;
        }
        bool unique() const {
            return this->get_use_count() == 1;
        }

    private:
        friend class weak_count<Ptr>;
        counted_ptr<Ptr>* pi;
};
template <typename Ptr> class shared_count; //同上

template <typename Ptr>
class weak_count {
    public:
        constexpr weak_count(): pi(nullptr) {}
        weak_count(const shared_count<Ptr>& r): pi(r.pi) {
            if(pi != nullptr)
                pi->weak_add_ref();
        }
        weak_count(const weak_count& r): pi(r.pi) {
            if(pi != nullptr)
                pi->weak_add_ref();
        }
        weak_count(weak_count&& r): pi(r.pi) {
            r.pi = nullptr;
        }
        ~weak_count() {
            if(pi != nullptr)
                pi->weak_release();
        }
        weak_count& operator=(const shared_count<Ptr>& r) {
            counted_ptr<Ptr>* tmp = r.pi;
            if(tmp != nullptr)
                tmp->weak_add_ref();
            if(pi != nullptr)
                pi->weak_release();
            pi = tmp;
            return *this;
        }
        weak_count& operator=(const weak_count& r) {
            counted_ptr<Ptr>* tmp = r.pi;
            if(tmp != nullptr)
                tmp->weak_add_ref();
            if(pi != nullptr)
                pi->weak_release();
            pi = tmp;
            return *this;
        }
        weak_count& operator=(weak_count&& r) {
            if(pi != nullptr)
                pi->weak_release();
            pi = r.pi;
            r.pi = nullptr;
            return *this;
        }
        void swap(weak_count& r) {
            tmp = r.pi;
            r.pi = pi;
            pi = tmp;
        }
        int get_use_count() const {
            return pi != nullptr ? pi->get_use_count() : 0;
        }
    private: 
        friend class shared_count<Ptr>;
        counted_ptr<Ptr>* pi;
};
template <typename T> class weak_ptr;

template <typename T>
class shared_ptr {
    public:
        constexpr shared_ptr(): ptr(0), refcount() {}
        constexpr shared_ptr(nullptr):shared_ptr() {}
        explicit shared_ptr(T* p): ptr(p), refcount(p) {}
        shared_ptr(const shared_ptr&) = default;
        shared_ptr(shared_ptr&& r):ptr(r.ptr), refcount() {
            refcount.swap(r.refcount);
            r.ptr = 0;
        }
        shared_ptr(const weak_ptr<T>& r): refcount(r.refcount) {
            ptr = r.ptr;
        }
        shared_ptr& operator=(const shared_ptr&) = default;
        shared_ptr& operator=(shared_ptr&& r) {
            shared_ptr(std::move(r)).swap(*this);
            return *this;
        }
        ~shared_ptr() = default;
        void reset() {
            shared_ptr().swap(*this);
        }
        void reset(T* p) {
            assert(p == 0 || p != ptr);
            shared_ptr(p).swap(*this);
        }
        T& operatpr*() const {
            assert(ptr != 0);
            return *ptr;
        }
        T* operator->() const {
            assert(ptr != 0);
            return ptr;
        }
        T* get() const {return ptr;}
        bool unique() const {return refcount.unique();}
        int use_count() const { return refcount.get_use_count();}
        explicit operator bool() const {return ptr == 0;}
        void swap(shared_ptr& other) {
            std::swap(ptr, other.ptr);
            refcount.swap(other.refcount);
        }
    private:
        friend class weak_ptr<T>;
        T* ptr;

        // shared_count通過counted_ptr來間接管理ptr指向資源
        shared_count<T*> refcount; 
};
template <typename T> class shared_ptr;

template <typename T>
class weak_ptr {
    public:
        constexpr weak_ptr(): ptr(nullptr), refcount() {}
        weak_ptr(const weak_ptr&) = default;
        weak_ptr(weak_ptr&& r): ptr(r.ptr), refcount(std::move(r.refcount)) {
            r.ptr = nullptr;
        }
        weak_ptr(const shared_ptr<T>& r): ptr(r.ptr), refcount(r.refcount) {}
        ~weak_ptr() = default; // 會自動調用weak_count的析構函數
        weak_ptr& operator=(const weak_ptr& r) = default;
        weak_ptr& operator=(const shared_ptr<T>& r) {
            ptr = r.ptr;

            // 調用weak_count的operator=(const shared_count&)函數
            refcount = r.refcount; 
            return *this;
        }
        weak_ptr& operator=(weak_ptr&& r) {
            ptr = r.ptr;
            refcount = std::move(r.refcount);
            r.ptr = nullptr;
            return *this;
        }
        shared_ptr<T> lock() const {
            // 間接利用構造函數shared_count(const weak_count&)檢查資源是否已被釋放
            return shared_ptr<T>(*this); 
        }
        int use_count() const { return refcount.get_use_count();}
        bool expired() const {return refcount.get_use_count() == 0;}
        void reset() {
            weak_ptr().swap(*this);
        }
        void swap(weak_ptr& s) {
            std::swap(ptr, s.ptr);
            refcount.swap(s.refcount);
        }
    private:
        friend class shared_ptr<T>;
        T* ptr;
        weak_count<T*> refcount;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章