智能指针之unique_ptr简单实现

文章详细介绍了C++中的unique_ptr智能指针,包括其独占所有权、不允许拷贝但支持移动构造的特点。通过示例展示了unique_ptr的构造、析构、移动构造和赋值操作,以及自定义删除器的实现,特别提到了对单个对象和一组对象的管理。此外,还提供了make_unique函数的模拟实现。
摘要由CSDN通过智能技术生成

一.unique_ptr的概念

unique_ptr 智能指针对象,可以独占的管理其所有权。

二.unique_ptr 特点∶
1 .基于排他所有权模式:两个指针不能指向同一个资源。
2 .由于独占对象的拥有权,所以不提供拷贝构造函数和左值赋值函数重载。

3 .提供移动构造和移动赋值函数。

4 .为了实现单个对象和一组对象的管理,添加了删除器类型。
5 .在容器保存指针是安全。
6 .unique_ptr具有->和*运算符重载符,因此它可以像普通指针一

样使用。

我们基于唯一性智能指针的特性去实现这些方法。

0.模板类的成员变量展示

template<class _Ty, class _Dx = Default_deleter<_Ty>>
class My_unique_ptr
{
public:

	/*explicit  指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
	*/
	explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
	~My_unique_ptr() { m_deleter(m_ptr); }
	
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using deleter_type = _Dx;
	pointer m_ptr;
	_Dx m_deleter;
};

1.构造函数,析构函数

/*explicit*/My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) 
{     std::cout << "creat My_unique_ptr";
}
~My_unique_ptr() 
{ 
    m_deleter(m_ptr); 
}

class Int
{
public:
	Int() :x_(0) { std::cout << "creat Int"; x_ += 1; }
	Int(int x) :x_(x) { std::cout << "creat Int"; }
	Int(int x, int y):x_(x) { std::cout << "creat Int"; }
	void Print()
	{
		std::cout << "Int::" << x_;
	}
public:
	int x_;
};

explicit:指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。如下:

My_unique_ptr<Int>tmp1 = new Int(12, 3);  //error :加上关键字不允许 隐式转换。

 2.为了满足智能指针的唯一性,不允许拷贝构造和赋值运算符的重载

代码:

My_unique_ptr(const My_unique_ptr&) = delete;
	My_unique_ptr& operator=(const My_unique_ptr&) = delete;

但提供了移动构造和移动赋值:
 

My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
	My_unique_ptr& operator=(My_unique_ptr&& other)
	{
		if (this != &other)
		{
			delete m_ptr;
			m_ptr = other.m_ptr;
			other.m_ptr = nullptr;
		}
		return *this;
	} //xxxx

3.几个方法:
 

pointer release()
	{
		pointer ptr = m_ptr; // 释放所有权不是将内存回收
		m_ptr = nullptr;
		return ptr;
	}
	pointer get()const
	{
		return m_ptr;
	}
	void swap(const pointer ptr)
	{
		std::swap(m_ptr, ptr);
	}
	pointer operator->()const
	{
		return m_ptr;
	}
	element_type& operator *()const
	{
		return *m_ptr;
	}

4.删除器的实现:
唯一性智能指针功能上支持一个或多个对象的管理。那么怎么管理一组对象?
这里我们用到的方法是:先在类中构建一个删除器对象,在智能指针类析构函数中利用仿函数和模板类和模板类的部分特化实现分别可以删除一个对象和一组对象。

template<class _Ty>
struct   Default_deleter
{
	void operator() (_Ty* ptr)
	{
		delete ptr;
		ptr = nullptr;
		std::cout << "destroyed";
	}
};
template<class _Ty>
struct   Default_deleter<_Ty[]>
{
	void operator ()(_Ty* ptr)
	{
		delete[]ptr;
		ptr = nullptr;
		std::cout << "destroyed ";
	}
};

智能化指针对象构建时如何区别一个和一组对象。答案是也用到了模板类的特化。

 完整代码如下:

#if 1
template<class _Ty>
struct   Default_deleter
{
	void operator() (_Ty* ptr)
	{
		delete ptr;
		ptr = nullptr;
		std::cout << "destroyed";
	}
};
template<class _Ty>
struct   Default_deleter<_Ty[]>
{
	void operator ()(_Ty* ptr)
	{
		delete[]ptr;
		ptr = nullptr;
		std::cout << "destroyed ";
	}
};
template<>
struct Default_deleter<FILE>
{
	void operator()(FILE* f)
	{
		fclose(f);
		std::cout << "fclose doc" << std::endl;
	}
};


template<class _Ty, class _Dx = Default_deleter<_Ty>>
class My_unique_ptr
{
public:

	/*explicit  指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
	*/
	explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
	~My_unique_ptr() { m_deleter(m_ptr); }
	My_unique_ptr(const My_unique_ptr&) = delete;
	My_unique_ptr& operator=(const My_unique_ptr&) = delete;
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using deleter_type = _Dx;
	pointer m_ptr;
	_Dx m_deleter;
public:
	My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
	My_unique_ptr& operator=(My_unique_ptr&& other)
	{
		if (this != &other)
		{
			delete m_ptr;
			m_ptr = other.m_ptr;
			other.m_ptr = nullptr;
		}
		return *this;
	}
	pointer release()
	{
		pointer ptr = m_ptr; // 释放所有权不是将内存回收
		m_ptr = nullptr;
		return ptr;
	}
	pointer get()const
	{
		return m_ptr;
	}
	void swap(const pointer ptr)
	{
		std::swap(m_ptr, ptr);
	}
	pointer operator->()const
	{
		return m_ptr;
	}
	element_type& operator *()const
	{
		return *m_ptr;
	}

};
template<class _Ty,class _Dx>
class My_unique_ptr<_Ty[],_Dx>
{
public:

	/*explicit  指定构造函数或转换函数 (C++11 起)或推导指引 (C++17 起)为显式,即它不能用于隐式转换和复制初始化。
	*/
	explicit My_unique_ptr(_Ty* ptr = nullptr) :m_ptr(ptr) { std::cout << "creat My_unique_ptr"; }
	~My_unique_ptr() { m_deleter(m_ptr); }
	My_unique_ptr(const My_unique_ptr&) = delete;
	My_unique_ptr& operator=(const My_unique_ptr&) = delete;
public:
	using pointer = _Ty*;
	using element_type = _Ty;
	using deleter_type = _Dx;
	pointer m_ptr;
	_Dx m_deleter;
public:
	My_unique_ptr(My_unique_ptr&& other) :m_ptr(other.m_ptr) { other.m_ptr = nullptr; }
	My_unique_ptr& operator=(My_unique_ptr&& other)
	{
		if (this != &other)
		{
			delete m_ptr;
			m_ptr = other.m_ptr;
			other.m_ptr = nullptr;
		}
		return *this;
	}
	pointer release()
	{
		pointer ptr = m_ptr; // 释放所有权不是将内存回收
		m_ptr = nullptr;
		return ptr;
	}
	pointer get()const
	{
		return m_ptr;
	}
	void swap(const pointer ptr)
	{
		std::swap(m_ptr, ptr);
	}
	_Ty& operator[](const size_t i)const 
	{
		return get()[i];
	}
	
};

template<class _Ty, class ... Types,enable_if_t<!is_array_v<_Ty>,int > =0>
My_unique_ptr<_Ty> My_make_unique(Types &&... Args)  //函数形式
{
	return My_unique_ptr<_Ty>(new _Ty(std::forward<Types>(Args)...));
}
//make_unique如何实现管理一组对象?
template<class _Ty,  enable_if_t<is_array_v<_Ty>, int > = 0>//is_array_v是否是数组类型
My_unique_ptr<_Ty> My_make_unique(const std::size_t size)  //函数形式
{
	using _Elem = remove_extent_t<_Ty>;//去除_Ty数组特性,保留类型 
	return My_unique_ptr<_Ty>(new _Elem[size]{});//new _Elem[size]{} 和new _Elem[size]区别
}

class Int
{
public:
	Int() :x_(0) { std::cout << "creat Int"; x_ += 1; }
	Int(int x) :x_(x) { std::cout << "creat Int"; }
	Int(int x, int y):x_(x) { std::cout << "creat Int"; }
	void Print()
	{
		std::cout << "Int::" << x_;
	}
public:
	int x_;
};
int main()
{
	//FILE* fptr;
	My_unique_ptr<Int[]>test(new Int[10]);
	//test.
	//My_unique_ptr<Int>tmp1 = new Int(12, 3); 
	//My_unique_ptr<FILE>fptr(fopen("lmy.txt", "w"));
	//fprintf(fptr.get(), "%d ,%d, %d", 10, 20, 30);
	/*My_unique_ptr<Int>tmp = My_make_unique<Int>(3);
	My_unique_ptr<Int>tmp1 = My_make_unique<Int>(12,3);*/
	//My_unique_ptr<Int[]>tmp2 = My_make_unique<Int[]>(12);
	//auto ptr = new Int[3];
	///*My_unique_ptr<char[]>pa(new char[10]);*/

	
	return 0;
}
#endif

注意:类模板函数模板的特化版本需要普通模板类或函数模板在其前面已经实现才可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值