【C++】智能指针

目录

一、先来看一下什么是智能指针

二、 auto_ptr

 1、C++98版本

2、C++11的auto_ptr

三、boost 库中的智能指针

1. scoped_ptr

2、shared_ptr(最好的智能指针)

四、C++11中新提供的智能指针

unique_ptr  

shared_ptr

std::shared_ptr的循环引用问题

weak_ptr弱指针

 shared_ptr 定制删除器  (智能指针真强大!!!)


一、先来看一下什么是智能指针

【C++】智能指针_第1张图片

 智能:        可以看到我们在申请资源之后并没有进行手动释放但是却没有内存的泄漏

 指针:        他明明是个对象,但用起来却像指针一样

可以发现,智能指针是很神奇的,下面让我们来看看他是怎样做到这些的吧

二、 auto_ptr

 1、C++98版本

原理如下:类中含有两个成员

【C++】智能指针_第2张图片

模拟:

【C++】智能指针_第3张图片

C++98有着很大的缺陷,主要就是拥有权的问题

当拥有权转移之后,原来的还能去访问到数据,这显然是一种藕断丝连的现象

【C++】智能指针_第4张图片

 这就导致了一种错觉,仿佛转移之后还拥有着使用权

2、C++11的auto_ptr

我们来看看C++11对这种现象是怎么处理的

【C++】智能指针_第5张图片

 我们可以发现C++11就改进了这一点,不存在藕断丝连这一说了

【C++】智能指针_第6张图片

三、boost 库中的智能指针

1. scoped_ptr

这个指针是个局部智能指针,就像个“貔貅”一样,只进不出,不允许拥有权的转移,构造拷贝都无法进行,底层是一个普通的指针

【C++】智能指针_第7张图片

 模拟实现:

template
class scoped_ptr
{
public:
	scoped_ptr(T* p = 0) : px(p)
	{
	}
	~scoped_ptr()
	{
		//检查释放
		//boost::checked_delete( px );
		delete px;
	}
public:
	T& operator*() const
	{
		return *px;
	}

	T* operator->() const
	{
		return px;
	}

	T* get() const
	{
		return px;
	}
public:
	typedef scoped_ptr this_type;
	void reset(T* p = 0)
	{
		//构造一个无名临时对象
		this_type(p).swap(*this);

		//this_type(p)  ==> scoped_ptr(p);
	}
	void swap(scoped_ptr& b) // never throws
	{
		T* tmp = b.px;
		b.px = px;
		px = tmp;
	}
private:
	scoped_ptr(scoped_ptr const&);
	scoped_ptr& operator=(scoped_ptr const&);  //私有的设置,不允许拷贝,赋值
	void operator==(scoped_ptr const&) const;
	void operator!=(scoped_ptr const&) const;
private:
	T* px;
};

2、shared_ptr(最好的智能指针)

底层原理图:内部是有一个引用计数器

引用计数器和之前学过的写实拷贝的地方实现原理很相似

【C++】智能指针_第8张图片

功能:     允许拷贝,赋值   还可以输出有几个引用

【C++】智能指针_第9张图片

 

 

模拟实现:

实现这个shared_ptr 智能指针  需要有四个类

1.   class shared_ptr类


#include"shared_count.h"

namespace zyf
{
	template
	class shared_ptr
	{
		typedef shared_ptr this_type;
	public:
		shared_ptr():px(0)
		{}
		template
		shared_ptr(Y* p) : px(p), pn(p)
		{
#ifdef DISPLAY
			cout << "Created shread_ptr obj." << endl;
#endif
		}
		~shared_ptr()
		{
#ifdef DISPLAY
			cout << "Free shread_ptr obj." << endl;
#endif
		}
		shared_ptr& operator=(const shared_ptr& r)
		{
			this_type(r).swap(*this);
			return *this;
		}
		shared_ptr(const shared_ptr &r):px(r.px),pn(r.pn)
		{}
	public:
		long use_count()const
		{
			return pn.use_count();
		}
	public:
		T& operator*()const
		{
			return *px;
		}
	public:
		void swap(shared_ptr& other)
		{
			std::swap(px, other.px);
			pn.swap(other.pn);
		}
	private:
		T* px;
		shared_count pn;//引用计数器对象
	};
}

2.   shared_count 类

//引用计数器类
class shared_count
{
public:
	shared_count():pi_(0)
	{}
	template
	shared_count(Y *p):pi_(0)
	{
		pi_ = new sp_counted_impl(p);//多态
#ifdef DISPLAY
		cout << "Created shread_count obj." << endl;
#endif
	}
	~shared_count()
	{
#ifdef DISPLAY
		cout << "Free shread_count obj." << endl;
#endif
		if (pi_)
			pi_->release();
	}
	shared_count(const shared_count& r):pi_(r.pi_)
	{
		if (pi_ != 0)
			pi_->add_ref_copy();
	}

public:
	long use_count()const
	{
		if (pi_ == nullptr)
			return 0;
		return pi_->use_count();		
	}
public:
	void swap(shared_count& r)
	{
		sp_counted_base* tmp = r.pi_;
		r.pi_ = pi_;
		pi_ = tmp;
	}
private:
	sp_counted_base* pi_;
};

3.   sp_counted_base类

class sp_counted_base
{
public:
	sp_counted_base() :use_count_(1)
	{
#ifdef DISPLAY
		cout << "Created sp_counted_base obj" << endl;
#endif
	}
	virtual ~sp_counted_base()
	{
#ifdef  DISPLAY
		cout << "Free sp_counted_base obj" << endl;
#endif
	}
public:
	void add_ref_copy()
	{
		use_count_++;
	}
	void release()
	{
		if (--use_count_ == 0)
		{
			delete this;
		}
	}
	long use_count()const
	{
		return use_count_;
	}
private:
	long use_count_;
	
};

4.sp_counted_impl类  ,这个类是继承  sp_sounted_base 类的

#include"sp_counted_base.h"

template
class sp_counted_impl : public sp_counted_base
{
public:
	sp_counted_impl(X *px):px_(px)
	{
#ifdef DISPLAY
		cout << "Created sp_sounted_impl obj." << endl;
#endif
	}
	~sp_counted_impl()
	{
		delete px_;
#ifdef DISPLAY
		cout << "Free sp_sounted_impl obj." << endl;
#endif
	}
private:
	X* px_;
};

四、C++11中新提供的智能指针

unique_ptr  

和scoped_ptr  一样 ,不允许拥有权的转移,和“貔貅”一样

shared_ptr

std::shared_ptr的线程安全问题

这里的线程不安全问题和之前的黄牛抢票现象是一样的:

【C++】智能指针_第10张图片

 

std::shared_ptr的循环引用问题

这里我们用一个双向列表的例子来举例说明什么是循环引用

我们先只创建两个节点类型,观察一下情况会是什么样子的。

【C++】智能指针_第11张图片

 我们发现,构造和析构函数能够正确的被调用,没有出现问题

这时候我们再来将这两个节点连接起来,观察一下会是怎么样的

【C++】智能指针_第12张图片

 我们很神奇的发现,不连还好,一连就出问题,析构函数没有被调用,这是什么情况呢?我们来探究一下

【C++】智能指针_第13张图片

 在函数调用结束后释放node1和node2智能指针所指向的资源的时候会给两个资源的计数器都减减,但是也只是减为1,两个节点内部的指针相互指向,到最后谁都释放不了。

根本原因:

  节点相互连接赋值的时候,因为内部的prev和 next 和节点的 node类型是一种类型,导致引用计数器会增加,

weak_ptr弱指针

解决这里的办法就是使用weak_ptr

weak_ptr 是为配合 shared ptr 而引入的一种智能指针,它更像是 shared ptr 的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator*和->。它的最大作用在于协助 shared ptr 工作,像旁观者那样观测资源的使用情况。

【C++】智能指针_第14张图片

上面我们知道了,使用weak_ptr 可以不增加引用计数 

使用了weak_ptr之后我们再来看看会是怎么样的

【C++】智能指针_第15张图片

 

 shared_ptr 定制删除器  (智能指针真强大!!!)

只要共享性智能指针对象的释放方式不能满足我们的要求,我们就可以取定制一个

1.  遇到数组类型的空间

【C++】智能指针_第16张图片

 这时候可以定制一个删除器

【C++】智能指针_第17张图片

 这时候就解决问题了

 

 2. 还可以解决不是new 出来的空间问题

比如是malloc出来的,这时候应该用free去对应

【C++】智能指针_第18张图片

 

其他问题也可以:  比如是文件描述符:  socketfd  、 newsockfd 、fp

【C++】智能指针_第19张图片

 

你可能感兴趣的:(C++,c++,开发语言)