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;
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章