shared_ptr,weak_ptr源码解析

来源:互联网 发布:精通matlab混合编程 编辑:程序博客网 时间:2024/05/16 10:10

下面的代码是我在看了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_counttemplate <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;};
0 0