C++实现智能指针(shared

xiaoxiao2021-02-28  91

C++标准库中又两种智能指针分别为:shared_ptr和unique_ptr

shared_ptr和unique_ptr之间最大的区别就是:shared_ptr允许共享指针,而unique_ptr则独占指针。

还有一个差异就是两种指针的删除器的差异。对于shared_ptr来说,删除器是可以重载的,所以其类型是在运行时绑定。而unique_ptr的删除器不能重载,且是unique_ptr类的一部分,在其编译时绑定。

根据以上这两点,我们对于实现也要采取不同的策略。

首先是shared_ptr的实现。

根据之前提到的,shared_ptr允许共享指针,那么我们就要做一个指针的引用计数,思路是使用new表达式来统计引用计数,每有一个指针被赋值则引用计数加一,相反,当指针被delete时引用计数减一。

先贴代码,如下:

#include <iostream> #include <functional> using namespace std; class deleter{ public: deleter()= default; template<typename T> void operator()(T* p)const{ delete p; p=nullptr; cout<<"new deleter"<<endl; } }; template<typename T> class New_shared_ptr{ public: New_shared_ptr()=default; explicit New_shared_ptr(T *p,function<void(T*)> d=deleter()):ptr(p),use(new size_t(1)),del(d){} //explicit New_shared_ptr(const New_shared_ptr&p):ptr(p.ptr),use(p.use),del(p.del){++*use;} //copy New_shared_ptr(New_shared_ptr&&p) noexcept :ptr(p.ptr),use(p.use),del(std::move(p.del)){ //move p.ptr=nullptr; p.use=nullptr; } T &operator*(); T* operator->(); New_shared_ptr &operator=(const New_shared_ptr&); New_shared_ptr &operator=(New_shared_ptr &&) noexcept ; operator bool() const { return ptr ? true : false;} T* get(New_shared_ptr&); bool unique(); size_t use_count(); void reset(){decrement_n_destroy();} //一共3个重载版本 void reset(T *p){ if(ptr!=p){ decrement_n_destroy(); ptr=p; use=new size_t(1); } } void reset(T *p,const function<void(T*)> &d){ reset(p); del=d; } ~New_shared_ptr(); private: T* ptr= nullptr; size_t *use=new size_t(0); //引用计数 function<void(T*p)> del{deleter()}; void decrement_n_destroy(); }; template <typename T> T* New_shared_ptr<T>::operator->() { return & this->operator *(); } template <typename T> T& New_shared_ptr<T>::operator*() { return *ptr; } template <typename T> New_shared_ptr<T>& New_shared_ptr<T>::operator=(const New_shared_ptr &rhs) { ++*rhs.use; if(--*use==0){ delete use; } use=rhs.use; del=rhs.del; return *this; } template <typename T> New_shared_ptr<T>& New_shared_ptr<T>::operator=(New_shared_ptr &&p) noexcept{ decrement_n_destroy(); std::swap(this->use,p.use); std::swap(this->ptr,p.ptr); std::swap(this->del,p.del); } template<typename T> T* New_shared_ptr<T>::get(New_shared_ptr&){ return ptr; } template <typename T> size_t New_shared_ptr<T>::use_count(){ return *use; } template <typename T> bool New_shared_ptr<T>::unique() { return *use==1; } template <typename T> New_shared_ptr<T>::~New_shared_ptr() { decrement_n_destroy(); } template <typename T> inline void New_shared_ptr<T>::decrement_n_destroy() { if(ptr) { if (--*use == 0) { delete use; del(ptr); } use = nullptr; ptr = nullptr; } } deleter是我们定义的删除器,也就是封装了指针的类,在这里用到了function模版类型。用来保存可调用对象,也就是保存我们自己定义可以用来重载的删除器,其形式可以是函数指针,函数,lambda表达式,bind函数以及重载了函数调用运算符的类。

其他部分的实现比较简单,主要注意的就是:要注意赋值和移动运算符中可能会出现自赋值的情况。

下面是unique_ptr的实现

首先说想法,unique_ptr是独占指针的,所以在实现的时候是不需要引用计数的,其次unique_ptr没有赋值操作(但是有移动操作!)

其次,unique_ptr的删除器是类的成员(可以自己指定)

代码如下:

#include <string> #include <iostream> #include "deleter.h" using namespace std; template<typename,typename> class New_unique_ptr; template<typename T,typename D> void swap(New_unique_ptr<T,D> &p1,New_unique_ptr<T,D> &p2){ std::swap(p1.ptr,p2.ptr); std::swap(p1.del,p2.del); } template<typename T,class D=deleter> class New_unique_ptr{ friend void swap<T,D>(New_unique_ptr<T,D> &p1,New_unique_ptr<T,D> &p2); public: New_unique_ptr()=default; explicit New_unique_ptr(T*p,D d1=deleter()):ptr(p),del(d1){} //unique_ptr没有赋值操作 New_unique_ptr(const New_unique_ptr& up)=delete; New_unique_ptr&operator=(const New_unique_ptr&)=delete; //移动操作要将指向的内容一起移动 New_unique_ptr(New_unique_ptr&& up)noexcept :ptr(up.ptr),del(up.del){up.ptr= nullptr;} New_unique_ptr& operator =(New_unique_ptr&& rhs) noexcept; New_unique_ptr&operator=(nullptr_t p)noexcept; //重载操作 T& operator*(){ return *ptr; } T* operator->(){ return &this->operator*();} ~New_unique_ptr(); T* get() const noexcept { return ptr;} T* release(); void reset(); void reset(T* p); private: T* ptr= nullptr; D del=deleter(); }; template<typename T,class D> New_unique_ptr<T,D>& New_unique_ptr<T,D>::operator=(New_unique_ptr&& rhs) noexcept{ if(this->ptr!=rhs.ptr){ del(ptr); ptr= nullptr; ::swap(*this,rhs); } return *this; }; template<typename T,class D> New_unique_ptr<T,D>& New_unique_ptr<T,D>::operator=(nullptr_t p)noexcept{ if(p==nullptr){ del(ptr); ptr=nullptr; } return *this; }; template<typename T,class D> T * New_unique_ptr<T,D>::release(){ T *p=ptr; ptr=nullptr; return p; }; template<typename T,class D> void New_unique_ptr<T,D>::reset(){ del(ptr); ptr=nullptr; }; template<typename T,class D> void New_unique_ptr<T,D>::reset(T* p){ del(ptr); ptr=p; }; template<typename T,class D> New_unique_ptr<T,D>::~New_unique_ptr(){ del(ptr); };删除器的实现如下:

#include <iostream> using namespace std; class deleter{ public: deleter(){} template<typename T> void operator()(T* p){ delete p; p=nullptr; cout<<"already delete"<<endl; } }; 说下自己的收获吧,造轮子对于刚学习完入门C++的人来说很重要,打好基础才是最重要的。实现完智能指针,自己对于模版,类,重载又有类新的认识。

还有一个我觉得比较容易忽视的一个点就是

对于operator->()的理解,成员访问运算符返回值是指针类型。对于它的原理大家可以再重新看一遍,可能会有不一样的收获哦。

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

最新回复(0)