c++【深度剖析shared_ptr】

shared_ptr解决了scoped_ptr管理单个对象的缺陷,且解决了防拷贝的问题。shared_ptr可以管理多个对象,并且实现了资源共享。

但是仍然存在一些问题,比如,我们熟悉的双向链表:

struct Node
{
Node(const int& value)
:_pNext(NULL)
,_pPre(NULL)
,_value(value)
{}
Node* _pNext;
Node* _pPre;
int _value;
};

这个双向链表对于shared_ptr会有什么影响呢?

1、shared_ptr的循环引用问题

先看如下代码:

#include
using namespace std;
#include
template
class Node
{
public:
	Node(const T& value)
		:_pNext(NULL)
		,_pPre(NULL)
		_value(value)
	{}
	shared_ptr> _pNext;
	shared_ptr> _pPre;
	T _value;
};

void FunTest()
{
	shared_ptr> sp1(new Node(1));
	shared_ptr> sp2(new Node(2));
	cout<_pNext = sp2;
	sp2->_pPre = sp1;
	cout<


运行结果:

c++【深度剖析shared_ptr】_第1张图片

这就是shared_ptr实现的双向链表的模型,在此处引起了循环引用的问题。

如图:

c++【深度剖析shared_ptr】_第2张图片


当分别创建完sp1,sp2后,它们各自的use_count为1;当再次执行

	sp1->_pNext = sp2;
	sp2->_pPre = sp1;

这两句后,sp1,sp2的use_count分别加为2;

此时,析构对象时use_count会减为1;但不等于0,所以它不会释放,这就导致了循环引用问题。

那么如何解决循环引用问题呢?我们又引出了另外一个智能指针:weak_ptr(它是一个弱指针,用来和shared_ptr搭配使用的)

2、解决循环引用问题

#include
using namespace std;
#include
template
class Node
{
public:
	Node(const T& value)
		:_value(value)
	{}
	T _value;
	weak_ptr> _pNext;
	weak_ptr> _pPre;
};

void FunTest()
{
	shared_ptr> sp1(new Node(1));
	shared_ptr> sp2(new Node(2));
	cout<_pNext = sp2;
	sp2->_pPre = sp1;
	cout<

运行结果:

c++【深度剖析shared_ptr】_第3张图片

其实,在shared_ptr和weak_ptr的引用计数的基类中,有两个计数:一个是_Uses,一个是_Weaks;

shared_ptr:当指向一片区域时,引用计数会使用_Uses来++;

weak_ptr:当指向一片区域时,引用计数会使用_Weaks来++;

最终看的还是use_count,使用weak_ptr时use_count仍为1;所以析构时可以成功释放。

3、定置删除器

原理:对于像文件类型的指针,用shared_ptr释放时,无法释放,因为在底层没有对文件指针的直接释放,所以得自己手动将其close掉。

void FunTest()
{
FILE* file = fopen("1.txt","r");
shared_ptr sp(file);
}

这时,就要使用我们的定置删除器:(此处用了STL的六大组件之一-----仿函数)

//成功的关闭文件:

#include
using namespace std;
#include

struct FClose
{
	void operator()(FILE *file)
	{
		fclose(file);
		cout<<"fclose()"< sp(file,FClose());
}

//类似的,对于我们malloc出来的空间,需要free掉时,同样也可以用仿函数的形式:

struct Free
{
       void operator()(void *ptr)
       {
              free(ptr);
			  cout<<"free()"< sp(p,Free());      
}

4、冒泡排序的升级版(仿函数的形式)

有时候,当面试官让你写一个冒泡排序的时候,你不知道面试官到底让你写的是升序还是降序,此时就比较尴尬了哈,你可以问一下面试官也是可以的,当然还有一种更巧妙的方法就是:你可以用仿函数的方式,把两种方式都实现了,需要哪种用哪种即可。

#include
using namespace std;
template
class Greater
{
public:
	bool operator()(const T&left,const T& right)
	{
		return left>right;
	}
};
template
class Less
{
public:
	bool operator()(const T&left,const T& right)
	{
		return left
void BubbleSort(T arr[],size_t size)
{
	for(size_t i = 0; i < size-1; i++)
	{
		for(size_t j = 0; j < size-i-1;++j)
		{
			if(Fun()(arr[j],arr[j+1]))
			{
				T tmp = arr[j];
				arr[j] = arr[j+1];
				arr[j+1] = tmp;
			}
		}
	}

}
void FunTest()
{
	int arr[] = {2,5,4,1,6,9,8,7};
	BubbleSort>(arr,sizeof(arr)/sizeof(arr[0]));
	BubbleSort>(arr,sizeof(arr)/sizeof(arr[0]));
}
int main()
{
	FunTest();
	return 0;
}

如果可以写成这种程度,肯定会使面试官眼前一亮。哈哈


你可能感兴趣的:(c++)