好记性不如铅笔头

C && C++, C++ Primer, 编程

C++智能指针笔记:std::unique_ptr

参考链接:

http://www.cplusplus.com/reference/memory/unique_ptr/ 】
unique_ptr和auto_ptr类似,使用还是比较方便的,而且可以自定义删除函数。

测试类:

class TestCls
{
public:
	string name;
	int x;
	TestCls(string _name):name(_name)
	{
		cout<<"TestCls "<<name.c_str()<<" Constructor Called\n";
	}
	~TestCls()
	 {
		 cout<<"TestCls "<<name.c_str()<<" Destructor Called\n";
	}
};

最简单的使用方法:

void testUniquePtrFunc()
{
	cout<<"enter testUniquePtrFunc\n";
	std::unique_ptr<TestCls> uniptr1(new TestCls("TEST"));
	cout<<"leave testUniquePtrFunc\n";
}

输出:

enter testUniquePtrFunc
TestCls TEST Constructor Called
leave testUniquePtrFunc
TestCls TEST Destructor Called

赋值,复制等逻辑:

void testUniquePtrFunc()
{
	cout<<"enter testUniquePtrFunc\n";
	std::unique_ptr<TestCls> uniptr1(new TestCls("TEST"));
	cout<<"uniptr1.get():"<<uniptr1.get()<<endl;

	std::unique_ptr<TestCls> uniptr2(std::move(uniptr1));
	cout<<"uniptr1.get():"<<uniptr1.get()<<endl;
	cout<<"uniptr2.get():"<<uniptr2.get()<<endl;

	cout<<"uniptr1:"<<uniptr1<<endl;//重载了bool操作符,可直接使用

	std::unique_ptr<TestCls> uniptr3 = std::move(uniptr2);
	cout<<"uniptr2.get():"<<uniptr2.get()<<endl;	
	cout<<"uniptr3.get():"<<uniptr3.get()<<endl;	

	cout<<"leave testUniquePtrFunc\n";
}

输出:

enter testUniquePtrFunc
TestCls TEST Constructor Called
uniptr1.get():0044CBE8
uniptr1.get():00000000
uniptr2.get():0044CBE8
uniptr1:0
uniptr2.get():00000000
uniptr3.get():0044CBE8
leave testUniquePtrFunc
TestCls TEST Destructor Called

常用函数:

void testUniquePtrFunc()
{
	cout<<"enter testUniquePtrFunc\n";

	TestCls *pTest = new TestCls("TEST");
	pTest->x = 10;
	cout<<"x:"<<pTest->x<<endl;

	std::unique_ptr<TestCls> uniptr1(pTest);
	pTest = NULL;//交给unique_ptr了,就不需要自己在管理了,可以防止误删除

	cout<<"x:"<<uniptr1->x<<endl;//可以直接调用参考类的共有方法或者变量。
	cout<<"x:"<<uniptr1.get()->x<<endl;//可以通过get方法获取原指针。

	TestCls &testCls = *uniptr1;
	testCls.x = 100;//可以通过*获取参考指针的引用。
	cout<<"x:"<<testCls.x<<endl;

	//可以通过release方法重新拿回指针,这样就需要自己管理
	pTest = uniptr1.release();
	delete pTest;
	pTest = NULL;

	TestCls *pTestA = new TestCls("A");
	TestCls *pTestB = new TestCls("B");
	std::unique_ptr<TestCls> uniptr2(pTestA);
	//调用reset,会先释放掉原有引用(pTestA),然后再持有新的引用(pTestB)
	uniptr2.reset(pTestB);

	//释放掉本地引用
	uniptr2.reset();
	
	cout<<"leave testUniquePtrFunc\n";
}

输出:

enter testUniquePtrFunc
TestCls TEST Constructor Called
x:10
x:10
x:10
x:100
TestCls TEST Destructor Called
TestCls A Constructor Called
TestCls B Constructor Called
TestCls A Destructor Called
TestCls B Destructor Called
leave testUniquePtrFunc

自定义删除函数:

我们首先看下unique_ptr的源码,部分源码如下:

template<class _Ty,
	class _Dx>	// = default_delete<_Ty>
	class unique_ptr
		: private _Unique_ptr_base<_Ty, _Dx,
			is_empty<_Dx>::value
				|| is_same<default_delete<_Ty>, _Dx>::value>
	{	// non-copyable pointer to an object
public:
	typedef unique_ptr<_Ty, _Dx> _Myt;
	typedef _Unique_ptr_base<_Ty, _Dx,
		is_empty<_Dx>::value
			|| is_same<default_delete<_Ty>, _Dx>::value> _Mybase;
	typedef typename _Mybase::pointer pointer;
	typedef _Ty element_type;
	typedef _Dx deleter_type;
	。。。。
}


这里可以知道删除函数默认为default_delete<_Ty>,然后我们可以看下default_delete<_Ty>的实现,如下,有两个,一个是单个元素,一个是数组形式的:

	// TEMPLATE CLASS default_delete
template<class _Ty>
	struct default_delete
	{	// default deleter for unique_ptr
	typedef default_delete<_Ty> _Myt;

	default_delete() _NOEXCEPT
		{	// default construct
		}

	template<class _Ty2>
		default_delete(const default_delete<_Ty2>&,
			typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
				void>::type ** = 0) _NOEXCEPT
		{	// construct from another default_delete
		}

	void operator()(_Ty *_Ptr) const _NOEXCEPT
		{	// delete a pointer
		static_assert(0 < sizeof (_Ty),
			"can't delete an incomplete type");
		delete _Ptr;
		}
	};

template<class _Ty>
	struct default_delete<_Ty[]>
	{	// default deleter for unique_ptr to array of unknown size
	typedef default_delete<_Ty> _Myt;

	default_delete() _NOEXCEPT
		{	// default construct
		}

	template<class _Other>
		void operator()(_Other *) const;	// not defined

	void operator()(_Ty *_Ptr) const _NOEXCEPT
		{	// delete a pointer
		static_assert(0 < sizeof (_Ty),
			"can't delete an incomplete type");
		delete[] _Ptr;
		}
	};

这里我们实现一个最简单的删除函数,如下:

template<class _Ty>
struct default_delete_custom
{	// default deleter for unique_ptr
	typedef default_delete_custom<_Ty> _Myt;

	default_delete_custom() _NOEXCEPT
	{	// default construct
	}

	template<class _Ty2>
	default_delete_custom(const default_delete_custom<_Ty2>&,
		typename enable_if<is_convertible<_Ty2 *, _Ty *>::value,
		void>::type ** = 0) _NOEXCEPT
	{	// construct from another default_delete
	}

	void operator()(_Ty *_Ptr) const _NOEXCEPT
	{	// delete a pointer
		static_assert(0 < sizeof (_Ty),
			"can't delete an incomplete type");
		delete _Ptr;

		cout<<"HI, I am default_delete_custom\n";
	}
};

然后调用:

void testUniquePtrFunc()
{
	cout<<"enter testUniquePtrFunc\n";

	TestCls *pTest = new TestCls("TEST");
	std::unique_ptr<TestCls, default_delete_custom<TestCls>> uniptr1(pTest);
	pTest = NULL;

	uniptr1.reset();
	
	cout<<"leave testUniquePtrFunc\n";
}

输出:

enter testUniquePtrFunc
TestCls TEST Constructor Called
TestCls TEST Destructor Called
HI, I am default_delete_custom
leave testUniquePtrFunc

源码学习:

比较多,随用随补吧。

Leave a Reply

14 − 9 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据