智能指针

1,什么是智能指针?

智能指针实际上是一个类,这个类的对象在构造函数时获取资源,同时在类内部重载 * 和 -> 操作符,用来获取资源。

并在析构函数中执行对资源的释放。

因为C++语言没有内存回收机制,所以总会导致内存泄漏,智能指针可以解决这个问题。

因为这个类的对象是在栈上创建的,那么在程序结束时,销毁类对象自动调用析构函数释放资源,就不会内存泄露了。

2,auto_ptr

中心思想:资源转移

代码实现:

template<class T>
class auto_ptr
{
	auto_ptr(T* ptr)
	:_ptr(ptr)
	{}

	T* operator->()//
	{
		return _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}
	auto_ptr( auto_ptr<T>& a)
	{
		_ptr = a._ptr;
		a.ptr = NULL;
	}
	auto_ptr<T>& operator=(auto_ptr<T>& a)
	{
		if (this != &a)
		{
			delete this->_ptr;
			this->_ptr = a._ptr;
			a._ptr = NULL;
		}
	}
	~auto_ptr()
	{
		delete _ptr;
	}
private:
	T* _ptr;
};

淘汰原因:

1、auto_ptr要求一个对象只能有一个拥有者,严禁一物二主

2、缺少对引用数和数组的支持。

3、不可将auto_ptr对象作为STL容器的元素。C++标准明确禁止这样做,否则可能会碰到不可预见的结果。(这一条晕死一大片)。

4、auto_ptr在被复制的时候会传输所有权

分析 * 和 -> 重载的意义

设 x 为一个智能指针的对象,那么 *x 就表示operator*(x),返回这个智能指针管理的资源。

对于->号,是用于访问资源中某个成员的,比如,管理的资源是一个结构体指针,访问这个结构体的某个成员时

例如:x->a    operator->()  ->a ,也就是说先返回返回结构体指针,在访问指定成员。

 

3,unique_ptr

中心思想:防止拷贝

实现代码

template<class T>
class unique_ptr
{
public:
	unique_ptr(const T* ptr)
	:_ptr(ptr)
	{}
	T* operator->()
	{
		return _ptr;
	}
	T& operator*()
	{
		return *_ptr;
	}

	~unique_ptr()
	{
		delete _ptr;
	}
protected://protected 使得在类外无法调用,只声明不定义,使得在类中不产生默认函数,也不执行
	unique_ptr(unique_ptr<T>& s);
	unique_ptr<T> operator=(unique_ptr<T>& s);

private:
	T* _ptr;
};

缺点不足

当我们真正的想要复制一个智能指针的时候,却无法办到了。

4,shared_ptr

中心思想:计数共享

代码实现

template<class T>
class shared_ptr
{
public:
	shared_ptr(T* ptr)
		:_ptr(ptr)
		, count(new int(1))
	{}

	T* operator->()
	{
		return _ptr;
	}

	T& operator*()
	{
		return *_ptr;
	}
	shared_ptr(shared_ptr<T>& a)
	{
		_ptr = a._ptr;
		count = a.count;
		++(*count);
	}

	shared_ptr<T>& operator=(shared_ptr<T>& a)
	{
		if (this != &a)
		{
			Release();
			_ptr = a._ptr;
			count = a.count;
			++(*count);
		}
	}

	~shared_ptr()
	{
		Release();
	}
private:
	void Release()
	{
		if (0 == --*(count))//如果*count不是等于0,那也已经减一了
		{
			delete _ptr;
			delete count;
			_ptr = NULL;
			count = NULL;
		}
	}
	T* _ptr;
	int* count;
};

缺点不足:循环引用

循环引用举例代码

struct ListNode
{
	shared_ptr<ListNode> _next;
	shared_ptr<ListNode> _pre;

	int _data;
	ListNode(int data)
		:_data(data)
		, _pre(NULL)
		, _next(NULL)
	{}
};

int main()
{
	shared_ptr<ListNode> cur(new ListNode(1));
	shared_ptr<ListNode> next(new ListNode(2));

	cur->_next = next;
	next->_pre = cur;
	return 0;
}

画图分析:

 智能指针

解决方法:weak_ptr

只需要在结构体中将shared_ptr换成 weak_ptr

只需要把Node结点里面的指针定义为weak_ptr类型就好,weak_ptr的构造析构不会影响引用计数的大小,当我们采用这种方式时,cur和next的引用计数始终为1,当我们想销毁时就可以随意操作啦!

struct ListNode
{
	shared_ptr<ListNode> _next;
	shared_ptr<ListNode> _pre;

	int _data;
	ListNode(int data)
		:_data(data)
		, _pre(NULL)
		, _next(NULL)
	{}
};