0
点赞
收藏
分享

微信扫一扫

基于引用计数的shared_ptr的简单实现

全栈顾问 2022-04-05 阅读 53
c++
//简易版的智能指针 多线程中智能指针的读取对象是不安全的
#include <iostream>
#include<bits/stdc++.h>
using namespace std;
template<typename T>//智能指针就是包装了指向T类型的指针
class Ptr{
public:
    Ptr(T*p= nullptr):mptr(p){
//        mcount=new size_t(1);//无论是什么内容都把这个初始值设为1.保证能对mcount进行销毁
        if(mptr!= nullptr) {
            mcount=new size_t(1);//只有内容不为空时才开始计数,这样确实是比较合理的
        }
        cout<<"first construct"<<endl;
        if(mptr!= nullptr) cout<<"info"<<*mptr<<endl;
    }
    ~Ptr(){
        (*mcount)--;
        if((*mcount)==0){
            delete mcount;
            delete mptr;
            cout<<"destroy all"<<endl;
        }
    }
    Ptr(const Ptr& other){//拷贝赋值是引用类型
        mptr=other.mptr;
        mcount=other.mcount;
        (*mcount)++;
        cout<<"copy"<<*mcount<<endl;
    }

    Ptr& operator=(const Ptr&other){//赋值函数, 为什么返回类型是引用 要判断是不是在同一块区间 回答:返回值是引用才可以连续进行赋值;形参类型是引用,避免重复调用拷贝构造函数
        if(this!=&other)//如果是同一个对象不进行实例操作。赋值的时候需要去进行判断赋值的对象和待赋值的对象是否已经相同,相同的话会错误的删除原来的内存空间,然后又进行了错误的赋值。
        {
            Ptr tmp(other);//避免地址判断,直接拷贝构造一个函数

            swap(tmp.mptr,mptr);
            swap(tmp.mcount,mcount);
            cout<<"addr not same"<<endl;

        }//保证了异常安全性,如果内存不够分配抛出异常不会修改原来的实例,保证了原来的数据安全性 成功分配内存后,自动销毁被赋值前对象的内存指向内容
        cout<<"assign"<<endl;
        return *this;  //返回Ptr的对象指针
    }


    T* operator->(){
        return  mptr;
    }
    //测试指针是否正确
    void test(){
        cout<<"test!"<<endl;
    }
    T& operator*(){
        return *mptr;
    }

private:
    T* mptr;
    size_t* mcount;
};
int main() {
    //int数据类型 测试类Ptr是否应用正确
//    Ptr<int> ptr(new int(2));//注意这里智能指针的构造方法
//    Ptr<int> ptr2(ptr);
//    cout<<"====="<<endl;
//    cout<<*ptr2<<endl;//对星号进行重载成功了
//    cout<<"====="<<endl;
//
//    cout<<"====="<<endl;
//    Ptr<int> ptr3(ptr);//在ptr3没有传递内容的指针构造的时候,默认是nullptr,所以只有构造函数,但是没有销毁函数,但是也不对,计数的new是在类里面的,所以要进行销毁。所以采取的策略就是mptr不为空才初始化计数为1,不然就是零。
//    ptr3=ptr;
//========//
//string 使用模板类定义自己的函数
//使用的时候可以看出来,智能指针仅仅是将指针进行了封装,智能指针定义的变量(比较小)是存在栈空间上,但是类里面有指针指向堆内存的内容(比较大),当超出作用域的时候就会自动调用析构函数,释放堆内存上面的空间
      Ptr<string> myptr(new string(10,'a'));//注意这里是采用构造函数的形式
      cout<<*myptr<<endl;
      Ptr<string> myptr2(new string(2,'b'));
      cout<<*myptr2<<endl;


      /*
       *标准库中使用智能指针shared_ptr和weak_ptr
       *
       * */
    shared_ptr<string> p= make_shared<string>(10,'a');
    weak_ptr<string> pw(p);
    cout<<pw.use_count()<<endl ;//弱引用可以观察次数,但不能直接访问内容,也就是*pw是非法的。
    shared_ptr<string> p2=pw.lock();//通过lock函数将弱引用转化成shared_ptr再进行使用
    cout<<*p2<<endl;
    return 0;
}

举报

相关推荐

0 条评论