手撕C++ shared_ptr智能指针


一、思路与流程

想要实现一个C++ shared_ptr智能指针类,首先先要回顾C++中提供的shared_ptr有哪些接口,以及实现了哪些功能,将需求全部列出来后再逐一击破。

  • 智能指针的构造方法
    1)默认构造,例如:shared_ptr<int> p1;
    默认初始化的智能指针保存的是一个空指针。
    2)有参构造,例如:shared_ptr<int> p1(ptr2);
    其中ptr2是一个int*类型的指针,但不建议使用普通指针初始化智能指针。
    3)拷贝构造,例如:shared_ptr<int> p2(sptr1);
    其中sptr1是一个shared_ptr类型的对象。
    4)移动构造,例如:shared_ptr<int> p2(std::move(sptr1));
    其中sptr1是一个shared_ptr类型的对象。如果使用移动构造函数,智能指针的计数值不会增加,相当于资源从智能指针sptr1转移到了智能指针p2中。

此外可以采用make_shared函数构造智能指针,这部分超出要实现的智能指针类之外,暂不考虑。

  • 赋值运算符
    shared_ptr的拷贝运算既支持左值运算又支持右值运算,测试如下:
// 用左值类型进行赋值操作
shared_ptr<int> p1 = make_shared<int>(10);
shared_ptr<int> p2 = p1;
cout << p2.use_count() << endl;     //2  引用计数为2
// 用右值类型进行赋值操作
shared_ptr<int> p1 = make_shared<int>(10);
shared_ptr<int> p2 = std::move(p1);
cout << p2.use_count() << endl;     //1  引用计数为1
  • 智能指针的其他操作
成员函数功能
p.get()返回智能指针中保存的普通指针
p.use_count()返回shared_ptr智能指针p中引用计数值
p.unique()智能指针中计数值是否为1,是则返回true,否则返回false
p2.swap(p1)交换智能指针p1和智能指针p2中的指针

二、代码实现

class shared_count{
public:
    shared_count():m_count(1){}
    ~shared_count() = default;
    void AddCount(){++m_count;}
    long GetCount(){return m_count;}
    long ReduceCount(){return --m_count;}

private:
    long m_count;
};

template <typename T>
class Shared_ptr{
public:
    //默认/有参构造函数
    Shared_ptr(T* ptr = nullptr):m_ptr(ptr){
        if(ptr){
            ref_count = new shared_count();
        }
    }
    ~Shared_ptr(){
        if(m_ptr && !ref_count -> ReduceCount()){
        //释放构造函数中创建的堆区内存
            delete m_ptr;     
            delete ref_count;
        }
    }
    //拷贝构造函数
    Shared_ptr(Shared_ptr<T>& sptr){
        m_ptr = sptr.m_ptr;
        if(m_ptr){
            ref_count = sptr.ref_count;
            ref_count -> AddCount();
        }
    }
    //移动构造函数
    Shared_ptr(Shared_ptr<T>&& sptr){
        m_ptr = sptr.m_ptr;
        if(m_ptr){
            ref_count = sptr.ref_count;
            sptr.m_ptr = nullptr;
            sptr.m_count = nullptr;
        }
    }
    //赋值运算符
    Shared_ptr& operator=(Shared_ptr& sptr){
        m_ptr = sptr.m_ptr;
        if(m_ptr){
            ref_count = sptr.ref_count;
            ref_count -> AddCount();
        }
        return *this;
    }
    Shared_ptr& operator=(Shared_ptr<T>&& sptr){
        m_ptr = sptr.m_ptr;
        if(m_ptr){
            ref_count = sptr.ref_count;
            sptr.m_ptr = nullptr;
            sptr.ref_count = nullptr;
        }
        return *this;
    }
    // 指针特性运算符重载
    T* operator ->(){
        return m_ptr;
    }
    T& operator *(){
        return *m_ptr;
    }

    //get函数
    T* get(){return m_ptr;}
    //use_count函数
    long use_count(){
        if(m_ptr){
            return ref_count -> GetCount();
        }
        return 0;
    }
    //unique函数
    bool unique(){
        if(m_ptr && ref_count -> GetCount() == 1)
            return true;
        return false;
    }
    //swap函数
    void swap(Shared_ptr<T>& sptr){
        swap(m_ptr, sptr.m_ptr);
        swap(ref_count,sptr.ref_count);
    }

private:
    T* m_ptr;
    shared_count* ref_count;
};

三、功能测试

  • 默认构造函数
Shared_ptr<int> sptr1;
cout << "sptr1.use_count() = " << sptr1.use_count() << endl;  //0
  • 与new结合进行初始化
Shared_ptr<int> sptr2(new int(10));
cout << "sptr2.use_count() = " << sptr2.use_count() << endl;  //1
  • 拷贝构造初始化
Shared_ptr<int> sptr2(new int(10));
Shared_ptr<int> sptr3(sptr2);
cout << "sptr3.use_count() = " << sptr3.use_count() << endl; //2
  • 移动构造初始化
Shared_ptr<int> sptr2(new int(10));
Shared_ptr<int> sptr4(std::move(sptr2));   
cout << "sptr4.use_count() = " << sptr4.use_count() << endl; //1
  • 拷贝复制运算符
Shared_ptr<int> sptr2(new int(10));
Shared_ptr<int> sptr5 = sptr2;
cout << "sptr5.use_count() = " << sptr5.use_count() << endl; //2
  • 移动拷贝运算符
Shared_ptr<int> sptr2(new int(10));
Shared_ptr<int> sptr6 = std::move(sptr2);
cout << "sptr6.use_count() = " << sptr6.use_count() << endl;  //1
  • 指针运算符
//*操作符
Shared_ptr<int> sptr2(new int(10));
cout <<  *sptr2 << endl;              //10

// ->操作符

```cpp
Shared_ptr<string> sptr7(new string("olivia"));
cout <<  sptr7 -> size() << endl;      //6

参考文章:
https://blog.csdn.net/readyone/article/details/111596876
https://blog.csdn.net/PX1525813502/article/details/124914944

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值