C++实现智能指针(shared_ptr和unique_ptr)与删除器

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


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值