shared

    xiaoxiao2021-04-14  83

    前面我们介绍智能指针的时候,说了两个智能指针分别是:auto_ptr和scoped_ptr,auto_ptr有问题,为此,scoped_ptr的出现解决了这个问题,scoped_ptr太霸道,不允许别人和他共用一块内存空间,所以,我们还得想办法解决这个问题。

    回想我们以前看过内容,当提到共用一块内存空间的时候,我们会想到什么?

    当然是深拷贝和浅拷贝了,最后我们是不是有给出了一个写时拷贝,就是通过引用计数的方法来实现共用一块内存空间的。对于这个问题,C++中也给出了一个相同方法的解决方案,这就是shared_ptr。

    首先,我们还是模拟一下shared_ptr:

    template <typename T> class SharedPtr { public: SharedPtr(T*ptr) :_Ptr(ptr) , _pcount(NULL) { if (_ptr) { _pcount=new int(1); } } SharedPtr(const SharedPtr<int> & sp) { _ptr = sp._ptr; _pcount = sp._pcount; ++(*_pcount); } ~SharedPtr() { if (0 == (--*_pcount)) { delete _ptr; delete _pcount; } } SharedPtr<T>& operator=(const SharedPtr<T>& sp) { if (this != &sp) { if (_ptr != nullptr) { if (_pcount == 0) { delete _ptr; delete _pcount; } } else { _ptr = sp._ptr; _pcount = sp._pcount; ++(*_pcount); } } return *this; } T&operator*() { return *_ptr; } T*operator->() { return *_ptr; } private: T* _ptr; int * _pcount; };

    定制删除器

    #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> using namespace std; //为解决文件指针 struct Fclose { void operator()(FILE*& fp) { cout<< "Fclose()" << endl; fclose(fp); fp = NULL; } }; //为解决malloc开辟的空间 template<class T> struct Free { void operator()(T*& p) { free(p); p = NULL; } }; //一般情况下(使用new动态开辟的空间) template<class T> class Delete { public : void operator()(T*& p) { delete p; p = NULL; } }; template<class T, class Destory = Delete<T> > class SharedPtr { public : SharedPtr(T* ptr = 0)//构造函数 :_ptr(ptr) ,_pCount(NULL) { if (_ptr) { _pCount = new int(1); } } SharedPtr(const SharedPtr<T>& sp)//拷贝构造函数 :_ptr(sp._ptr) , _pCount(sp._pCount) { if (_ptr) { ++GetRef(); } } //sp1 = sp2 SharedPtr<T>& operator=(const SharedPtr<T>& sp) { //可有三种情况:①sp1._ptr = NULL ②sp1的引用计数为1 ③sp1的引用计数大于1 if (this != &sp) { Release(); _ptr = sp._ptr; _pCount = sp._pCount; ++GetRef(); } return *this; } //辅助函数 void Release() { if (_ptr && --GetRef() == 0) { Destory()(_ptr); delete _pCount; _pCount = NULL; } } //析构函数 ~SharedPtr() { Release(); } int& GetRef() { return *_pCount; } private: T* _ptr; int* _pCount; }; void Test2() { FILE* sp1 = fopen("test.txt", "rb"); SharedPtr<FILE, Fclose> sp2(sp1); int* sp3 = (int*)malloc(sizeof(int)); SharedPtr<int, Free<int> >sp4(sp3); int* sp5 = new int(1); SharedPtr<int> sp6(sp5); } int main() { Test2(); return 0; }

    循环引用

    通过引用计数,我们解决了智能指针共享一块空间的问题,不过,shared_ptr还是有点问题,那就是循环引用的问题,什么是循环引用的问题呢?先来看一个例子:

    struct Node { int _data; shared_ptr<Node> _next; shared_ptr<Node> _prev; }; void FunTest() { shared_ptr<Node> sp1(new Node); shared_ptr<Node> sp2(new Node); cout << sp1.use_count() << endl; cout << sp2.use_count() << endl; sp1->_next = sp2; sp2->_prev = sp1; cout << sp1.use_count() << endl; cout << sp2.use_count() << endl; }

    我们先定义一个双链表节点,然后,我们再创建两个节点,并且让其链接起来,之后,我们再想要释放这两个节点的时候,会发现一个很有意思的现象,那就是,释放sp1的时候,必须先释放sp2,而想要释放sp2,那么必须先释放sp1,这就是循环引用的例子。

    如图:

    这是我画的两个节点,sp1的nest指向sp2,同时,sp2的prev指向sp1。那么sp1所指向的内存就被两个指针所管理,分别是:sp1和sp2->_prev;同样的,sp2所指向的内存空间就会被sp2和sp1->_nest所管理。

    如果现在想要释放的是sp1,那么释放内存的时候其实是将其引用计数减去1,不是将这段空间释放。

    那么,如何解决这个问题呢?

    这里就不得不说:weak_ptr 了。

    转载请注明原文地址: https://ju.6miu.com/read-670061.html

    最新回复(0)