• 【C++】实现unqiue_ptr


    C++中的辅助类型

    default_delete (C++11)

    MyDeletor() = default;给了一个默认构造函数
    Object(const Object &) = delete //属于C11新添加的功能。告诉编译我要做什么
    
    • 1
    • 2
    template<class _Ty>
    class MyDeletor
    {
    public:
    	MyDeletor() = default;//表示默认构造
    	void operator()(_Ty * ptr)const
    	{
    		if (ptr != NULL)
    		{
    			delete ptr;
    		}
    	}
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    template<class _Ty>
    class MyDeletor<_Ty[]>
    {
    public:
    	MyDeletor() = default;//表示默认构造
    	void operator()(_Ty* ptr)const
    	{
    		if (ptr != NULL)
    		{
    			delete []ptr;
    		}
    	}
    
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    模拟unique_ptr(泛化版本)----对单一对象的处理

    1. 模板中有两个参数,一个是指向对象类型,一个是删除器类型。
    2. 私有成员一个是指针,一个是删除器成员。
    3. 模拟unique_ptr的特性,不能使用拷贝构造和赋值构造,将其删除
    4. 在析构函数中,不为空就调用删除器
    template<class _Ty, class _Dx = MyDeletor<_Ty> >
    class my_unique_ptr
    {
    public:
    	//类型重命名
    	using pointer = _Ty*;      //typedef _Ty* pointer
    	using element_Type = _Ty;   //typedef _Ty element_Type
    	using delete_Type = _Dx;     //typedef _Dx delete_Type 删除器类型
    private:
    	_Ty* _Ptr;
    	_Dx _myDeletor;//删除器
    public:
    
    	my_unique_ptr(pointer _P = NULL) :_Ptr(_P) {}
    	my_unique_ptr(const my_unique_ptr& ptr) = delete;   //因此不能进行赋值操作
    	my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
    	~my_unique_ptr()
    	{
    		if (_Ptr != NULL)
    		{
    			_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
    			_Ptr = NULL;
    		}
         }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    观察器

    删除器

    用于析构被管理对象的删除器(普通和常性)

         _Dx& get_deletor()
    	{
    		return _myDeletor;
    	}
    	_Dx& get_deletor()const
    	{
    		return _myDeletor;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    *和->重载(引用和指向)

        _Ty& operator*()const
    	{
    		return *_Ptr;
    	}
    	_Ty operator->()
    	{
    		return  _Ptr;//&**this
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    获取当前指针

    pointer get()
    	{
    		return _Ptr;
    	}
    
    • 1
    • 2
    • 3
    • 4

    重载bool运算符

    operator bool()const
    	{
    		return _Ptr != NULL;
    	}
    	};
    
    int main()
    {
    	my_unique_ptr<int> op;
    	my_unique_ptr<int> op2(new int(10));
    	if (op) {}//if(op.operator bool())就可以判断真假
    	if (op2) {}
    	op2 != nullptr;  //不可以比较,因为只能指针和指针比较,(nullptr相当于空指针)
    	//op2是一个bool类型
    	op2 != false;//是可以的
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    请添加图片描述

    修改器

    释放当前资源

    将资源转移给old,然后自身指针置为空

    pointer release()
    	{
    		_Ty* old = _Ptr;
    		_Ptr = NULL;
    		return old;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    重置指针的指向

    old指向当前指针所指对象(如果不这样做,会导致指针所指的对象不能被删除)
    当前指针指向新的指针所指的对象
    在调用删除器删掉old

    void reset(pointer _p = NULL)//重置
    	{
    		pointer old = _Ptr;//防止该空间无法被释放
    		_Ptr = _p;
    		if (old != NULL)
    		{
    			//_myDeletor(old);
    			get_deleter()(old);
    		}
    
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    是否使用内联,取决于系统需不需要节省开栈清栈的时间。

    移动构造

    my_unique_ptr(my_unique_ptr&& _Y)
    	{
    		Ptr = _Y._Ptr;
    		_Y._Ptr = NULL;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    移动赋值

    my_unique_ptr& operator=(my_unique_ptr&& _Y)
    {
    		if (this == _Y) return *this;
    		reset(_Y.release());
    		return *this;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    交换

    void swap(my_unique_ptr _Y)
    	{
    		std::swap(_Ptr, _Y._Ptr);
    		std::swap(_myDeletor, _Y._myDeletor);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5

    部分特化版本:

    template<class _Ty, class _Dx = MyDeletor<_Ty> >
    class my_unique_ptr<_Ty[],_Dx>
    {
    public:
    	//类型重命名
    	using pointer = _Ty*;      //typedef _Ty* pointer
    	using element_Type = _Ty;   //typedef _Ty element_Type
    	using delete_Type = _Dx;     //typedef _Dx delete_Type 
    private:
    	_Ty* _Ptr;
    	_Dx _myDeletor;
    public:
    
    	my_unique_ptr(pointer _P = NULL) :_Ptr(p) {}
    	my_unique_ptr(const my_unique_ptr& ptr) = delete;   //因此不能进行赋值操作
    	my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
    	~my_unique_ptr()
    	{
    		if (_Ptr != NULL)
    		{
    			_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
    			_Ptr = NULL;
    		}
         }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    提供到被管理数组的有索引访问(数组版本)

    _Ty& operator[](size_t _Idx)const
    {
       return _Ptr[_Idx];
    }
    
    • 1
    • 2
    • 3
    • 4

    可变参数类型

    
    template<class _Ty a>
    template<class _Ty a ,class _Uy b>
    template<class _Ty a ,class _Uy b,class Ty c>
    fun(12)
    fun(12,12)
    fun(12,12,12)
    fun(12,12,12,12);就没有可适用的模板了。
    而可变参数模板类型正是来解决这个问题。
    template<class _Ty...>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    构造的指针可以指向多个参数的对象,再构造时传入的参数可变。

    template<class _Ty,class ..._Type>
    	my_unique_ptr<_Ty>my_make_unique(_Type&& ..._arrys)
    	{
    		return my_unique_ptr<_Ty>(new_Ty(arys...));
    	}
    int main()
    {
    	my_unique_ptr<Object> op1 = my_make_unique<Object>();//调动的是默认构造
    	my_unique_ptr<Object> op2 = my_make_unique<Object>(1); //可变参数
    	my_unique_ptr<Object> op3 = my_make_unique<Object>(1, 2, 3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    测试:

    测试1:返回具名对象,会调用移动构造创建将亡值对象。

    my_unique_ptr<Object> fun()
    {   
    	my_unique_ptr<Object> opa(new Object(10));
    	return opa;//此时调用的移动构造函数,构建将亡值,来获取opa对象的内容
    	                             //函数结束opa就会被析构
    }
    //测试1
    int main()
    {
    	my_unique_ptr<Object>opb;
    	opb = fun();
    }
        1.调用调用my_unique_ptr创建opb对象,进fun()函数内,调用Object的构造函数创建不具名对象,并初始化
        2.调用my_unique_ptr的构造函数创建opa对象,并指向不具名对象的地址
        3.返回opa,调用移动构造,构建将亡值对象,指向opa指向的不具名对象地址。
        4.程序结束,析构opa,返回到调用点
        5.调用移动赋值,将将亡值对象保存的值传给opb,析构将亡值对象。
        6.析构opb对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    请添加图片描述

    测试2:如果使用右值引用返回:(不要这样做)

    如下

    my_unique_ptr<Object> &&fun()
    {   
    	my_unique_ptr<Object> opa(new Object(10));
    	return std::move(opa);  //使用右值引用返回,将不具名对象转化具名对象,因此opa析构,右值引用只是一个别名,自然也访问不到opa所指的对象地址。
    	}
    	int main()
    {
    	my_unique_ptr<Object>opb;
    	opb = fun();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    测试三:直接返回不具名对象,不需要调用移动构造

    my_unique_ptr<Object> funb()   //可以输出,将不具名对象资源调用移动赋值直接给objb
    {
    	return my_unique_ptr<Object> (new Object(5));
    }
    int main()
    {
    	my_unique_ptr<Object>opb;
    	opb = fun();
    }
        1.调用调用my_unique_ptr创建opb对象,进fun()函数内,调用Object的构造函数创建不具名对象,并初始化
        2.调用my_unique_ptr的构造函数创建不具名对象,并指向不具名对象的地址
        3.返回不具名对象
        4.调用移动赋值,将不具名对象保存的值传给opb,析构不具名对象
        6.析构opb对象
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    请添加图片描述

    注意:

    不允许使用引用和右值引用,因为只要加引用,就不让不具名对象转换为具名对象,就不会按照移动赋值的方式将不具名对象指向的内容提交给objb。而是函数结束,便会析构掉,拿着它的别名,资源已经被释放,找不到了。
    所以,不管在任何时候,都不要用引用或者右值引用返回一个不具名对象。

    源码

    泛化版本

    template<class _Ty>
    class MyDeletor
    {
    public:
    	MyDeletor() = default;//表示默认构造
    	void operator()(_Ty * ptr)const
    	{
    		if (ptr != NULL)
    		{
    			delete ptr;
    		}
    	}
    };
    template<class _Ty>
    class MyDeletor<_Ty[]>
    {
    public:
    	MyDeletor() = default;//表示默认构造
    	void operator()(_Ty* ptr)const
    	{
    		if (ptr != NULL)
    		{
    			delete []ptr;
    		}
    	}
    
    };
    //模拟unique_ptr
    template<class _Ty, class _Dx = MyDeletor<_Ty> >
    class my_unique_ptr
    {
    public:
    	//类型重命名
    	using pointer = _Ty*;      //typedef _Ty* pointer
    	using element_Type = _Ty;   //typedef _Ty element_Type
    	using delete_Type = _Dx;     //typedef _Dx delete_Type   //删除器类型
    private:
    	_Ty* _Ptr;
    	_Dx _myDeletor;  //删除器
    public:
    
    	my_unique_ptr(pointer _P = NULL) :_Ptr(_P) {}
    	my_unique_ptr(const my_unique_ptr& ptr) = delete;   //因此不能进行赋值操作
    	my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
    	~my_unique_ptr()
    	{
    		if (_Ptr != NULL)
    		{
    			_myDeletor(_Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
    			_Ptr = NULL;
    		}
    	}
    	my_unique_ptr(my_unique_ptr&& _Y)
    	{
    		_Ptr = _Y._Ptr;
    		_Y._Ptr = NULL;
    	}
    	my_unique_ptr& operator=(my_unique_ptr&& _Y)
    	{
    		if (this == &_Y) return *this;
    		reset(_Y.release());
    		return *this;
    	}
    	_Dx& get_deletor()
    	{
    		return _myDeletor;
    	}
    	_Dx& get_deletor()const
    	{
    		return _myDeletor;
    	}
    	_Ty& operator*()const
    	{
    		return *_Ptr;
    	}
    	_Ty operator->()
    	{
    		return  _Ptr;//&**this
    	}
    	pointer get()
    	{
    		return _Ptr;
    	}
    	operator bool()const
    	{
    		return _Ptr != NULL;
    	}
    	pointer release()
    	{
    		_Ty* old = _Ptr;
    		_Ptr = NULL;
    		return old;
    	}
    	void reset(pointer _p = NULL)//重置
    	{
    		pointer old = _Ptr;
    		_Ptr = _p;
    		if (old != NULL)
    		{
    			//_myDeletor(old);
    			get_deletor()(old);
    		}
    
    	}
    	void swap(my_unique_ptr _Y)
    	{
    		std::swap(_Ptr, _Y._Ptr);
    		std::swap(_myDeletor, _Y._myDeletor);
    	}
    };
    //特化版本:访问一组对象
    template<class _Ty, class _Dx = MyDeletor<_Ty> >
    class my_unique_ptr<_Ty[],_Dx>
    {
    public:
    	//类型重命名
    	using pointer = _Ty*;      //typedef _Ty* pointer
    	using element_Type = _Ty;   //typedef _Ty element_Type
    	using delete_Type = _Dx;     //typedef _Dx delete_Type 
    private:
    	_Ty* _Ptr;
    	_Dx _myDeletor;
    public:
    
    	my_unique_ptr(pointer _P = NULL) :_Ptr(p) {}
    	my_unique_ptr(const my_unique_ptr& ptr) = delete;   //因此不能进行赋值操作
    	my_unique_ptr& operator=(const my_unique_ptr& ptr) = delete;//也不能进行=号操作
    	~my_unique_ptr()
    	{
    		if (_Ptr != NULL)
    		{
    			_myDeletor(Ptr);//局部对象加()调用的是void operator()(Ty* ptr)const
    			_Ptr = NULL;
    		}
         }
         my_unique_ptr(my_unique_ptr&& _Y)
    	{
    		_Ptr = _Y._Ptr;
    		_Y._Ptr = NULL;
    	}
    	my_unique_ptr& operator=(my_unique_ptr&& _Y)
    	{
    		if (this == &_Y) return *this;
    		reset(_Y.release());
    		return *this;
    	}
    	_Dx& get_deletor()
    	{
    		return _myDeletor;
    	}
    	_Dx& get_deletor()const
    	{
    		return _myDeletor;
    	}
    	_Ty& operator*()const
    	{
    		return *_Ptr;
    	}
    	_Ty operator->()
    	{
    		return  _Ptr;//&**this
    	}
    	pointer get()
    	{
    		return _Ptr;
    	}
    	operator bool()const
    	{
    		return _Ptr != NULL;
    	}
    	pointer release()
    	{
    		_Ty* old = _Ptr;
    		_Ptr = NULL;
    		return old;
    	}
    	void reset(pointer _p = NULL)//重置
    	{
    		pointer old = _Ptr;
    		_Ptr = _p;
    		if (old != NULL)
    		{
    			//_myDeletor(old);
    			get_deletor()(old);
    		}
    
    	}
    	void swap(my_unique_ptr _Y)
    	{
    		std::swap(_Ptr, _Y._Ptr);
    		std::swap(_myDeletor, _Y._myDeletor);
    	}
    	_Ty& operator[](size_t _Idx)const
      {
       return _Ptr[_Idx];
       }
    };
    template<class _Ty,class ..._Type>
    my_unique_ptr<_Ty>my_make_unique(_Type&& ..._arrys)
    {
       return my_unique_ptr<_Ty>(new_Ty(_arrys...));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
  • 相关阅读:
    C# async / await 用法
    基于鹈鹕优化的BP神经网络(分类应用) - 附代码
    计算机毕业设计 基于SSM的问卷调查管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解
    h264文件提取一帧帧数据
    用Unity做一个萌萌哒游戏(附资源)
    MyBatis-Plus之Sql注入器
    java计算机毕业设计合同管理源码+mysql数据库+系统+lw文档+部署
    k8s-9 ingress-nginx 特性
    专精特新新企业技术创新发展趋势研究分析讲座详情
    react hook: useCallback
  • 原文地址:https://blog.csdn.net/weixin_52958292/article/details/127624167