模板共享指针(shared_ptr)原理实现

  最近在书中看到关于智能指针的描述,由于之前没有使用过智能指针,便通过调试源代码(源代码的实现有点杂乱,并不能以最简单直观的方式呈现)了解原理后,以简单直接的方式写了一个shared_ptr指针类。

关于shared_ptr指针的几点介绍:
   1.共享指针在拷贝函数中拷贝已有的指针对象参数地址达到共享数据(简单的说就是一块类对象地址由多个指针同时指向并且使用);
   2.共享指针内部通过计数形式来记录共享调用类对象内存的次数(创建共享指针对象时计数为1,每被拷贝一次(赋值给别的新对象)计数加1),每释放一个共享指针对象计数减1,当指针计数为0时释放共享调用类对象内存;
   3.shared_ptr类共享指针内存及共享计数内存在没有通过手动释放的情况下,将会通过虚拟析构函数来做内存释放工作。

下面贴上代码:

template<typename _Tp>
	class new_allocator//采用了模板类特有的内存分配类,保证分配产生碎片变少的同时并且提高运行效率
	{
	public:
		typedef size_t     size_type;
		typedef ptrdiff_t  difference_type;
		typedef _Tp*       pointer;
		typedef const _Tp* const_pointer;
		typedef _Tp&       reference;
		typedef const _Tp& const_reference;
		typedef _Tp        value_type;

		template<typename _Tp1>
		struct rebind
		{ typedef new_allocator<_Tp1> other; };

		new_allocator() throw() { }

		new_allocator(const new_allocator&) throw() { }

		template<typename _Tp1>
		new_allocator(const new_allocator<_Tp1>&) throw() { }

		~new_allocator() throw() { }

		pointer
			address(reference __x) const { return &__x; }

		const_pointer
			address(const_reference __x) const { return &__x; }

		// NB: __n is permitted to be 0.  The C++ standard says nothing
		// about what the return value is when __n == 0.
		pointer
			allocate(size_type __n, const void* = 0)
		{ 
			/*if (__builtin_expect(__n > this->max_size(), false))
			__throw_bad_alloc();*/

			return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp)));
		}

		// __p is not permitted to be a null pointer.
		void
			deallocate(pointer __p, size_type)
		{ ::operator delete(__p); }

		size_type
			max_size() const throw() 
		{ return size_t(-1) / sizeof(_Tp); }

		// _GLIBCXX_RESOLVE_LIB_DEFECTS
		// 402. wrong new expression in [some_] allocator::construct
		void 
			construct(pointer __p, const _Tp& __val) 
		{ ::new((void *)__p) _Tp(__val); }

#ifdef __GXX_EXPERIMENTAL_CXX0X__
		template<typename... _Args>
		void
			construct(pointer __p, _Args&&... __args)
		{ ::new((void *)__p) _Tp(forward<_Args>(__args)...); }
#endif

		void 
			destroy(pointer __p) { __p->~_Tp(); }
	};




	template<typename _Tp>
	class allocator: public new_allocator<_Tp>
	{
	public:
		typedef size_t     size_type;
		typedef ptrdiff_t  difference_type;
		typedef _Tp*       pointer;
		typedef const _Tp* const_pointer;
		typedef _Tp&       reference;
		typedef const _Tp& const_reference;
		typedef _Tp        value_type;

		template<typename _Tp1>
		struct rebind
		{ typedef allocator<_Tp1> other; };

		allocator() throw() { }

		allocator(const allocator& __a) throw()
			: __glibcxx_base_allocator<_Tp>(__a) { }

		template<typename _Tp1>
		allocator(const allocator<_Tp1>&) throw() { }

		~allocator() throw() { }

		// Inherit everything else.
	};




	class Ref_count_base/* 指针计数管理 */
	{
	public:
		Ref_count_base():m_ncount(0)
		{

		}
		long GetCount()//获取当前计数
		{
			return m_ncount;
		}
		int ResetCount(int nAdd)//设置当前计数 1. 计数增加1 ,0. 计数减少1
		{
			if (1 == nAdd)
			{
				++m_ncount;
			}
			else
			{
				--m_ncount;
			}
			return m_ncount;
		}
	private:
		long m_ncount;//计数变量
	};


	template <typename _Ty>
	class Point_Base/* 在这里做指针计数与数据对象的结合并且都是采用动态分配的方式(通过使用地址)达到数据共享  */
	{
	public:
		Point_Base()
		{
			ref_count = 0;
		}
		typedef _Ty* pointer;
		typedef _Ty& reference;
	protected:
		pointer m_obj;//共享类指针对象
		Ref_count_base* ref_count;//计数类指针对象
	};




template <typename Pointer>
class Test_Pointer : public Point_Base<Pointer>//模板指针调用类
{
	typedef Test_Pointer<Pointer> test_pointer;
	typedef Pointer* pointer;
	typedef Pointer& reference;
	typedef allocator<Pointer> alloc_type;
public:
	
	virtual ~Test_Pointer()//每次类退出前会执行一次析构函数
	{
		if (!ref_count)/* 已经释放的情况下直接返回 */
		{
			return ;
		}
		int ncount = ref_count->ResetCount(0);
		if (0 == ncount && 0 != m_obj)//如果计数为0而且共享类指针还没有释放,那么这个共享指针没被共享和计数指针一起释放掉
		{
			m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); 
			delete ref_count;
		}
	}
	Test_Pointer():m_nCritical(0),m_nCriticalRun(1),m_nSize(1)//无参数构造函数 分配一个共享类内存
	{
		if (0 == ref_count)
		{
			ref_count = new Ref_count_base;
		}
		ref_count->ResetCount(1);
		m_obj = m_alloc.allocate(1);
	}

	template<class _Ux>
	explicit Test_Pointer(_Ux *_Px):m_nCritical(0),m_nCriticalRun(1)//有参数构造函数 根据输入的数量进行分配内存
	{
		if (0 == ref_count)
		{
			ref_count = new Ref_count_base;
		}
		ref_count->ResetCount(1);
		m_obj = m_alloc.allocate(*_Px);
		m_nSize = *_Px;
	}
	pointer operator->() /* 增加临时临界区,在多个线程中保证智能指针数据同步,关于调用类对象的数据需要在线程中增加真正的临界区来同步化 */
	{
		if (1 == m_nCriticalRun)
		{
			int nRun = m_nCritical;
			++m_nCritical;
			while (nRun != 0 && nRun != m_nCritical)
				;
			--m_nCritical;
		}
		return m_obj;
	}

	Test_Pointer(test_pointer& _Other)//复制构造函数
	{
		*this = _Other;
		ref_count->ResetCount(1);
	}
	void SetCritical(int nRun);//调用共享类成员数据保护临界区 1. 启动 0. 不启动 默认1(在多线程情况下可以看出效果)
	void Reset();
	template<class _Ux>
	void Reset(_Ux *_Px)//把共享计数减一后 ,分配新的共享类内存
	{
		if (ref_count && 0 < ref_count->GetCount() && 0 != m_obj)
		{
			ref_count->ResetCount(0);

			if (0 == ref_count->GetCount())/* 如果在共享指针计数减一为0的情况(属于没有在别的地方被使用) ,释放共享指针 和共享指针计数 */
			{
				m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); 
				delete ref_count;
			}
		}

		
			ref_count = new Ref_count_base;
		
		ref_count->ResetCount(1);
		m_obj = m_alloc.allocate(*_Px);
		m_nSize = *_Px;
	}
private:	
	alloc_type m_alloc;//内存分配
	volatile int m_nCritical;//临界区
	volatile int m_nCriticalRun;//临界区是否运行
	int m_nSize;//共享类对象内存大小(个数)
};
template <typename Pointer>
inline void Test_Pointer<Pointer>::SetCritical(int nRun)
{
	m_nCriticalRun = nRun;
}
template <typename Pointer>
inline void Test_Pointer<Pointer>::Reset()/* 调用无参数Reset 把共享指针计数减一 并且把共享指针计数与共享指针赋值为0 */
{
	if (ref_count && 0 < ref_count->GetCount() && 0 != m_obj)
	{
		ref_count->ResetCount(0);
		
		if (0 == ref_count->GetCount())/* 如果在共享指针计数减一为0的情况(属于没有在别的地方被使用) ,释放共享指针 和共享指针计数 */
		{
			m_alloc.deallocate(m_obj,sizeof(Pointer) * m_nSize); 
			delete ref_count;
		}
		m_obj = 0;
		ref_count = 0;/* 因为已经脱离了上一个共享指针,所以共享指针 和共享指针计数都指向空 */
		m_nSize = 0;
	}
}

使用方法:

Test_Pointer<int> testint(new int(2));
	Test_Pointer<int> testint1 = testint;
	Test_Pointer<int> testint2 = testint1;
	Test_Pointer<int> testint3 = testint;//指向到此处可以看到4个类对象共享类指针地址与共享计数相同
	testint.Reset();//共享计数减一 并且共享类指针地址与共享计数地址赋值为0
	testint1.Reset(new int(4));//共享计数减一 并且共享类指针地址与共享计数地址赋值为0 , 然后分配新的共享类指针内存 与 共享计数
	testint1.SetCritical(0);	
发布了94 篇原创文章 · 获赞 206 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/a29562268/article/details/71190031