C++ unique_ptr介绍及仿写

Posted Jqivin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++ unique_ptr介绍及仿写相关的知识,希望对你有一定的参考价值。


一、unique_ptr的使用

(1)构造函数不能进行隐式转换。
(2)unique_ptr可以指向动态数组。因为unique_ptr有unique_ptr<T[]>重载版本,销毁动态对象时调用delete[]。
(3)unique_ptr无拷贝语义,但提供了移动语义,所以可作为函数返回值。与容器在一块使用时要注意。
(4)谨慎使用智能指针的get与release方法
当使用get方法返回裸指针时,智能指针并没有释放指向对象的所有权,所以我们必须小心使用裸指针以避免程序崩溃。但通过unique_ptr.release()方法返回的裸指针,需要我们自己delete删除对象,因为调用release方法后,该unique_ptr不再拥有对象的所有权。

class Object
{
private:
	int value;
public:
	Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
	~Object() { cout << "destruct Object" << endl; }
	int Value() { return value; }
	const int  Value() const { return value; }

};
int main()
{
	unique_ptr<Object> pO(new Object(10));
	unique_ptr<Object> pO2(new Object(20));
	unique_ptr<int> pi(new int(1));
	cout << pO->Value() << endl;
	cout << *pi << endl;
	//pO = pO2;								//编译不通过,不能拷贝构造或者赋值
	pO = std::move(pO2);					//移动之后pO2就析构掉了
	//cout << pO2->Value() << endl;			 //错误:如果不注释掉就执行失败,因为pO2已经没有对象资源的所有权了
	cout << pO->Value() << endl;
	int* p = pi.release();
	// cout << *pi << endl;					//错误:release之后也会释放资源的所有权
	cout << "*p=" << *p << endl; delete p;

	cout << endl;
	unique_ptr<int[]> ps1(new int[10]{ 1,2,3,4,5,6,7,8,9,10 });
	//cout << *ps1 << endl;    特化版本不重载* ->
	for (int i = 0; i < 10; i++)
	{
		cout << ps1[i] << " ";
	}
	cout << endl;
	Object* Obj = new Object[]{ 10,20,30 };
	delete[]Obj;
	unique_ptr<Object[] > pobj(new Object[]{ 10,20,30 });

	cout << pobj[0].Value() << endl;;

	return 0;
}

结果
在这里插入图片描述

二、unique_ptr类的成员方法

1.非特化版本

在这里插入图片描述

2.特化版本

缺少运算符*,->的重载,多了[]的重载;
在这里插入图片描述

get()函数:只是得到unique_ptr指向的资源
release():函数是释放unique_ptr指向的资源,返回值是指向的资源
swap():交换两个unique_ptr指向的资源,参数是unique_ptr类型
reset():重置unique_ptr指向的资源,先释放原来的资源,然后将指针指向新的资源。参数是指针类型,而不是unique_ptr类型。

int main()
{
	unique_ptr<int> up(new int(10));
	int* p = up.get();        //get()只是得到unique_ptr指向的资源
	cout << "*p=" << *p << endl;    //10
	cout << "*up=" << *up << endl;  //10

	unique_ptr<int> up2(new int(20));
	up2.swap(up);            //交换资源
	cout << *up <<" " << *up2 << endl;   //20  10

	up2.reset(new int(30));   
	cout << *up2 << endl;   //30

	int* p2 = up.release();    //release释放unique_ptr对资源的所有权
	cout << "*p2=" << *p2 << endl;     //20
	cout << "*up=" << *up << endl;     //出错,已经不拥有资源了
	return 0;
}

三、仿写

#include<iostream>
using namespace std;
#if 1
namespace jqw
{
//默认的删除器
template <class _Ty>
struct default_delete
{public:
	void operator()(_Ty* ptr)const
	{
		delete ptr;
	}
};
//数组的删除器
template <class _Ty>
struct default_delete<_Ty[]>
{
	void operator()(_Ty* ptr)const 
	{
		delete []ptr;
	}
};

template <class _Ty, typename _Dp  = default_delete<_Ty>>
class unique_ptr
{
private:
	_Ty* _Ptr;
public:
	typedef _Ty* pointer;
	typedef _Ty element_type;
	typedef _Dp delete_type;
	delete_type get_deleter() { return delete_type(); } //删除器获取函数
	//构造函数  不可以隐式转换
	explicit unique_ptr(_Ty* ptr = nullptr):_Ptr(ptr){}
	//析构函数
	~unique_ptr()
	{
		if (_Ptr)
		{
			//delete _Ptr;
			get_deleter()(_Ptr);

		}
	}
	//拷贝构造和赋值函数delete掉
	unique_ptr(unique_ptr<_Ty>& p) = delete;
	unique_ptr<_Ty>& operator=(const unique_ptr<_Ty>& p) = delete;
	//移动构造函数和移动赋值
	unique_ptr(unique_ptr<_Ty>&& p)
	{
		if (_Ptr != p._Ptr)
		{
			//delete _Ptr;		//XXXXXXXXXXX
			get_deleter()(_Ptr);
			_Ptr = p._Ptr;
			p._Ptr = nullptr;
		}
	}
	unique_ptr<_Ty>& operator=(unique_ptr<_Ty>&& p)
	{
		if (this != &p)
		{
			//delete _Ptr;
			get_deleter()(_Ptr);
			_Ptr = p._Ptr;
			p._Ptr = nullptr;
		}
		return *this;
	}
	
	//获取资源
	pointer get() const
	{
		return _Ptr;
	}
	//判断智能指针是否拥有资源  ?????、返回类型
	explicit  operator bool() const
	{
		return _Ptr != nullptr;
	}
	//重载运算符* ->
	_Ty* operator->() const
	{
		return get();
	}
	const _Ty& operator*() const
	{
		return *_Ptr;
	}
	//释放函数
	pointer release()
	{
		_Ty* tmp = this->_Ptr;
		this->_Ptr = nullptr;
		return tmp;
	}
	//重置资源
	void reset(_Ty* p = nullptr)
	{
		//delete _Ptr;			//XXXXX
		get_deleter()(_Ptr);
		_Ptr = p;
	}
	//交换
	void swap(unique_ptr& _u)
	{
		std::swap(_Ptr, _u._Ptr);
	}
};
//
template <class _Ty, typename _Dp>
class unique_ptr<_Ty[],_Dp>   //特化版本,用户可以自己写 _Dp 删除器
{
private:
	_Ty* _Ptr;
public:
	typedef _Ty* pointer;
	typedef _Ty element_type;
	typedef _Dp delete_type;
	delete_type get_deleter() { return delete_type(); } //删除器获取函数
	//构造函数
	explicit unique_ptr(_Ty* ptr = nullptr) :_Ptr(ptr) {}
	//析构函数
	~unique_ptr()
	{
		if (_Ptr)
		{
			//delete _Ptr;
			get_deleter()(_Ptr);

		}
	}
	//拷贝构造和赋值函数delete掉
	unique_ptr(unique_ptr<_Ty>& p) = delete;
	unique_ptr<_Ty>& operator=(const unique_ptr<_Ty>& p) = delete;
	//移动构造函数和移动赋值
	unique_ptr(unique_ptr<_Ty>&& p)
	{
		if (_Ptr != p._Ptr)
		{
			//delete _Ptr;		//XXXXXXXXXXX
			get_deleter()(_Ptr);
			_Ptr = p._Ptr;
			p._Ptr = nullptr;
		}
	}
	unique_ptr<_Ty>& operator=(unique_ptr<_Ty>&& p)
	{
		if (this != &p)
		{
			delete _Ptr;
			_Ptr = p._Ptr;
			p._Ptr = nullptr;
		}
		return *this;
	}

	//获取资源
	pointer get() const
	{
		return _Ptr;
	}
	//判断智能指针是否拥有资源  ?????、返回类型
	explicit  operator bool() const
	{
		return _Ptr != nullptr;
	}
	//重载运算符* ->
	_Ty* operator->() const
	{
		return get();
	}
	const _Ty& operator*() const
	{
		return *_Ptr;
	}
	//释放函数
	pointer release()
	{
		_Ty* tmp = this->_Ptr;
		this->_Ptr = nullptr;
		return tmp;
	}
	//重置资源
	void reset(_Ty* p = nullptr)
	{
		//delete _Ptr;			//XXXXX
		get_deleter()(_Ptr);
		_Ptr = p;
	}
	//交换
	void swap(unique_ptr& _u)
	{
		std::swap(_Ptr, _u._Ptr);
	}
	_Ty& operator[](int index)
	{
		return _Ptr[index];
	}
};
}
class Object
{
private:
	int value;
public:
	Object(int val = 0) :value(val) { cout << "construct Object" << endl; }
	~Object() { cout << "destruct Object" << endl; }
	int Value() { return value; }
	const int  Value() const { return value; }
	
};
int main()
{
	jqw::unique_ptr<Object> pO(new Object(10));
	jqw::unique_ptr<Object> pO2(new Object(20));
	jqw::unique_ptr<int> pi(new int(1));
	cout << pO->Value() << endl;
	cout << *pi << endl;
	//pO = pO2;								//编译不通过,不能拷贝构造或者赋值
	pO = std::move(pO2);					//移动之后pO2就析构掉了
	//cout << pO2->Value() << endl;			 //错误:如果不注释掉就执行失败,因为pO2已经没有对象资源的所有权了
	cout << pO->Value() << endl;
	int* p = pi.release();
	// cout << *pi << endl;					//错误:release之后也会释放资源的所有权
	cout << "*p=" << *p << endl; delete p;

	cout << endl;
	jqw::unique_ptr<int[]> ps1(new int[10]{ 1,2,3,4,5,6,7,8,9,10 });
	cout << *ps1 << endl;
	for (int i = 0; i < 10; i++)
	{
		cout << ps1[i] << " ";
	}
	cout << endl;
	Object* Obj = new Object[]{ 10,20,30 };
	delete []Obj;
	jqw::unique_ptr<Object[] > pobj(new Object[]{ 10,20,30 });

	cout << pobj[0].Value() << endl;;
	
	return 0;
}
#endif

结果:和系统提供的一致,(仿写特化版本没有删除* ->的重载)
在这里插入图片描述

以上是关于C++ unique_ptr介绍及仿写的主要内容,如果未能解决你的问题,请参考以下文章

C++ 智能指针 (unique_ptr)

如何将 unique_ptr 从一组移动到另一组? (C++)

c++ unique_ptr 参数传递

使用 std::unique_ptr 的 C++ Pimpl Idiom 不完整类型

C++笔记-auto_ptr&unique_ptr&shared_ptr&shared_ptr基本用法

C++笔记-auto_ptr&unique_ptr&shared_ptr&shared_ptr基本用法