【C++智能指针】实现unqiue_ptr

C++中的辅助类型

default_delete (C++11)

MyDeletor() = default;给了一个默认构造函数
Object(const Object &) = delete //属于C11新添加的功能。告诉编译我要做什么
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(泛化版本)----对单一对象的处理

  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;
		}
     }
};

观察器

删除器

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

     _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;
	}

重载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;//是可以的
}

请添加图片描述

修改器

释放当前资源

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

pointer release()
	{
		_Ty* old = _Ptr;
		_Ptr = NULL;
		return old;
	}

重置指针的指向

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

void reset(pointer _p = NULL)//重置
	{
		pointer old = _Ptr;//防止该空间无法被释放
		_Ptr = _p;
		if (old != NULL)
		{
			//_myDeletor(old);
			get_deleter()(old);
		}

	}

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

移动构造

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;
	}

交换

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;
		}
     }
};

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

_Ty& operator[](size_t _Idx)const
{
   return _Ptr[_Idx];
}

可变参数类型


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...>

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

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:返回具名对象,会调用移动构造创建将亡值对象。

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对象

请添加图片描述

测试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();
}

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

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对象

请添加图片描述

注意:

不允许使用引用和右值引用,因为只要加引用,就不让不具名对象转换为具名对象,就不会按照移动赋值的方式将不具名对象指向的内容提交给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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
unique_ptrC++11 引入的智能指针之一,用于管理动态分配的对象。它的使用场景主要有以下几个方面: 1. 独占资源管理:unique_ptr 的最大特点是独占所指向的对象,即同一时间只能有一个 unique_ptr 指向一个对象。这种独占性使得 unique_ptr 在资源管理方面非常有用,例如在函数返回时,可以将对象的所有权从一个 unique_ptr 转移给另一个 unique_ptr,从而避免了手动释放资源的麻烦和潜在的内存泄漏。 2. 防止内存泄漏:由于 unique_ptr 的特性,可以保证当 unique_ptr 超出作用域时,它所管理的对象会自动被销毁。这避免了手动释放资源的繁琐和容易出错的问题,有效地防止了内存泄漏。 3. 与 RAII(资源获取即初始化)原则结合:RAII 是一种 C++ 资源管理的编程范式,unique_ptr 与之紧密结合。通过将资源(如动态分配的对象、文件句柄等)的所有权交给 unique_ptr,可以保证在任何情况下都能正确释放资源,无论是正常执行还是异常情况。 4. 支持自定义删除器:unique_ptr 允许为其管理的对象指定自定义的删除器,即在对象销毁时执行特定的清理操作。这在需要特殊资源管理行为的情况下非常有用,例如通过自定义删除器可以使用 delete[] 释放动态分配的数组。 总之,unique_ptr 提供了一种简单、安全、高效的方式来管理动态分配的对象,避免了手动资源管理所可能引发的问题,是 C++ 代码中常用的智能指针之一。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值