简单仿写共享性智能指针——《shared_ptr》

引用计数的对象没有被释放。:引用计数类对象是所有共享智能指针所共有的,因此在堆区通过指针共享。释放时一般通过weak_ptr释放。(注:make_shared缺点之一,shared_ptr销毁时,weak_ptr还存活,则引用计数类对象与资源对象所在的同一片空间会延迟释放(只有最后一个 weak_ptr 离开作用域时, 内存才会被释放. 原本强引用减为 0 时就可以释放的内存, 现在变为了强引用, 弱引用都减为 0 时才能释放,))、
在这里插入图片描述

std::shared_ptr 是通过指针保持对象共享所有权的智能指针。多个 shared_ptr 对象可占有同一对象。具体参考 《std::shared_ptr

#include <iostream>
#include <atomic>

// 仿写shared_ptr
namespace TR {
	// 引用计数类
	template<typename T>
	class RefCnt {
	private:
		T* mPtr;		// 指向对象的指针
		std::atomic<int> mCnt;	// 原子操作 ++i {指向对象的指针和引用计数}
	public:
		// 构造函数,空指针引用计数为0,否则为1
		RefCnt(T* ptr = nullptr) noexcept :mPtr(ptr), mCnt(0)
		{
			if (ptr != nullptr) mCnt = 1;
		}
		// atomic内部函数,获得当前mCnt瞬间值
		int load() const noexcept { return mCnt.load(); }
		// 重置引用计数
		void reset(int ref = 1)noexcept { mCnt = ref; }
		// 引用计数增加
		void addRef()noexcept { ++mCnt;/* mCnt++ */ }
		// 引用计数减少
		int delRef()noexcept { return --mCnt; }
		// 析构函数
		~RefCnt()noexcept {}
	};

	// 删除器类	-针对单个对象	// 一元仿函数
	template<typename T>
	struct MyDeletor {
		void operator()(T* ptr)  const noexcept 
		{
			delete ptr; 
		}
	};

	// 删除器类	-针对多个对象	// 一元仿函数
	template<typename T>
	struct MyDeletor<T[]> {
		void operator()(T* ptr)  const noexcept
		{
			delete[] ptr;
		}
	};


	// 智能指针类				// 默认的删除方法
	template<typename T, typename Deletor = MyDeletor<T>>
	class shared_ptr {
	private:	// 成员变量
		T* mPtr;
		RefCnt<T>* mpRefCnt;
	private:	
		// 返回一个删除器对象
		Deletor Get_deletor() { return Deletor(); }
	private:
		// 释放资源函数
		void release()
		{
			if (get() != nullptr) {	// 空指针,忽略
				if (0 == mpRefCnt->delRef())	// 引用计数器为0时,释放资源
				{
					Get_deletor()(mPtr);	// 使用删除器进行释放
					delete mpRefCnt;
				}
				mPtr = nullptr;
				mpRefCnt = nullptr;
			}
		}

	public:
		// 构造
		shared_ptr(T* ptr = nullptr) noexcept :mPtr(ptr)
		{
			if(ptr != nullptr)	// 空指针不生成引用计数实例
				mpRefCnt = new RefCnt<T>(ptr);	// 引用计数类生成实例
		}
		// 拷贝构造
		shared_ptr(const shared_ptr& _Y)noexcept
			:mPtr(_Y.mPtr), mpRefCnt(_Y.mpRefCnt)
		{	// 如果是空指针,不生成引用计数实例
			if (mPtr != nullptr) mpRefCnt->addRef();
		}
		~shared_ptr()noexcept
		{
			this->release();
		}
		// 移动构造
		shared_ptr(shared_ptr&& _Y) noexcept
		{
			mPtr = _Y.mPtr;
			mpRefCnt = _Y.mpRefCnt;
			_Y.mPtr = nullptr;
			_Y.mpRefCnt = nullptr;
		}
		// 赋值函数
		shared_ptr& operator=(const shared_ptr& _Y)noexcept
		{
			//if (this != &_Y)	// 防止自赋值
			//{
			//	release();	// 删除原有资源(删除、或引用计数减一)
			//	if (mPtr != nullptr)     // 资源非空,进行赋值
			//	{
			//		mPtr = _Y.mPtr;		// 赋值资源
			//		mpRefCnt = _Y.mpRefCnt;// 赋值引用计数
			//		mpRefCnt->addRef();	// 引用计数++
			//	}
			//}
			//return *this;

		// 库提供实现方法:调用拷贝,生成临时对象,交换两对象的值
			shared_ptr(_Y).swap(*this);	
			return *this;
		}
		// 移动赋值函数
		shared_ptr& operator=(shared_ptr&& _Y) noexcept
		{
			//mPtr = _Y.mPtr;
			//mpRefCnt = _Y.mpRefCnt;
			//_Y.mPtr = nullptr;
			//_Y.mpRefCnt = nullptr;
			//return *this;

		// 库提供实现方法:调用移动构造,生成临时对象,交换两对象的值
			shared_ptr(std::move(_Y)).swap(*this);
			return *this;
		}
		// 重置函数
		void reset(T* p)noexcept
		{	// 库提供实现方法:调用构造函数生成临时对象,交换两对象的值
			shared_ptr(p).swap(*this);
		}
		// 交换函数
		void swap(shared_ptr& _Right)noexcept
		{
			std::swap(mPtr, _Right.mPtr);	// 交换资源
			std::swap(mpRefCnt, _Right.mpRefCnt);	// 交换引用计数实例
		}
		// 是否独占
		bool unique()const noexcept
		{
			return static_cast<long>(this->use_count()) == 1;
		}

	public:
		// 重载运算符
		T* get() const noexcept { return mPtr; }
		T& operator*()  const noexcept { return *get(); }
		T* operator->()  const noexcept { return get(); }
		explicit operator bool()  const noexcept { return get() != nullptr; }
		long use_count() const noexcept { return mpRefCnt == nullptr ? 0 : mpRefCnt->load(); }

	};

	/* ----------------------------- 多对象(数组)版本 ---------------------------- */

	// 智能指针类				// 默认的删除方法
	template<typename T, typename Deletor >
	class shared_ptr<T[], Deletor> {
	private:	// 成员变量
		T* mPtr;
		RefCnt<T>* mpRefCnt;
	private:
		// 返回一个删除器对象
		Deletor Get_deletor() { return Deletor(); }
	private:
		// 释放资源函数
		void release()
		{
			if (get() != nullptr) {	// 空指针,忽略
				if (0 == mpRefCnt->delRef())	// 引用计数器为0时,释放资源
				{
					Get_deletor()(mPtr);	// 使用删除器进行释放
					delete mpRefCnt;
				}
				mPtr = nullptr;
				mpRefCnt = nullptr;
			}
		}

	public:
		// 构造
		shared_ptr(T* ptr = nullptr) noexcept :mPtr(ptr)
		{
			if (ptr != nullptr)	// 空指针不生成引用计数实例
				mpRefCnt = new RefCnt<T>(ptr);	// 引用计数类生成实例
		}
		// 拷贝构造
		shared_ptr(const shared_ptr& _Y)noexcept
			:mPtr(_Y.mPtr), mpRefCnt(_Y.mpRefCnt)
		{	// 如果是空指针,不生成引用计数实例
			if (mPtr != nullptr) mpRefCnt->addRef();
		}
		~shared_ptr()noexcept
		{
			this->release();
		}
		// 移动构造
		shared_ptr(shared_ptr&& _Y) noexcept
		{
			mPtr = _Y.mPtr;
			mpRefCnt = _Y.mpRefCnt;
			_Y.mPtr = nullptr;
			_Y.mpRefCnt = nullptr;
		}
		// 赋值函数
		shared_ptr& operator=(const shared_ptr& _Y)noexcept
		{
			shared_ptr(_Y).swap(*this);
			return *this;
		}
		// 移动赋值函数
		shared_ptr& operator=(shared_ptr&& _Y) noexcept
		{
			shared_ptr(std::move(_Y)).swap(*this);
			return *this;
		}
		// 重置函数
		void reset(T* p)noexcept
		{	
			shared_ptr(p).swap(*this);
		}
		// 交换函数
		void swap(shared_ptr& _Right)noexcept
		{
			std::swap(mPtr, _Right.mPtr);	// 交换资源
			std::swap(mpRefCnt, _Right.mpRefCnt);	// 交换引用计数实例
		}
		// 是否独占
		bool unique()const noexcept
		{
			return static_cast<long>(this->use_count()) == 1;
		}

	public:
		// 重载运算符
		T* get() const noexcept { return mPtr; }
		T& operator*()  const noexcept { return *get(); }
		//T* operator->()  const noexcept { return get(); }
		T& operator[](int Idx)const noexcept { return get()[Idx]; }
		explicit operator bool()  const noexcept { return get() != nullptr; }
		long use_count() const noexcept { return mpRefCnt == nullptr ? 0 : mpRefCnt->load(); }

	};

}

测试类:

// 测试类
class Object {
private:
	int mval;
public:
	Object(int i = 0)
		:mval(i) { std::cout << "construction()  val: " << mval << std::endl; }
	~Object() { std::cout << "~destruct()  val: " << mval << std::endl; }
	const int& getVal() { return mval; }
};

测试用例:

int main()
{
	// 测试:空指针相互赋值
	TR::shared_ptr<Object> a;
	TR::shared_ptr<Object> b;
	a = b;
	std::cout << a.use_count() << " " << b.use_count() << std::endl;
		// 相关函数:赋值函数,
		// 构造函数:如果传入空指针则不生成RefCnt对象
		// use_count:如果是空指针,返回0
	
	// 正常赋值
	TR::shared_ptr<Object> a1(new Object(1));
	TR::shared_ptr<Object> b1;
	b1 = a1;
	std::cout << a1.use_count() << " " << b1.use_count() << std::endl;

	// 拷贝赋值 & 移动赋值
	TR::shared_ptr<Object> osp1(new Object(2));
	TR::shared_ptr<Object> osp2(std::move(osp1));
	TR::shared_ptr<Object> osp3;
	osp3 = std::move(osp2);
	std::cout << osp3->getVal() << std::endl;
	std::cout << osp1.use_count() << " " << osp2.use_count() 
		<< " " << osp3.use_count() << std::endl;

	// 是否独占
	TR::shared_ptr<Object> c(new Object(3));
	std::cout << "c 是否独占: " <<std::boolalpha << c.unique() << std::endl;

	// 交换
	TR::shared_ptr<Object> d(new Object(4));
	TR::shared_ptr<Object> e(new Object(5));
	d.swap(e);
	std::cout << "d: "<< d->getVal() << " " << "  e: " << e->getVal() << std::endl;

	// 重置
	TR::shared_ptr<Object> f(new Object(6));
	std::cout << "f: " << f->getVal() << std::endl;
	f.reset(new Object(8));
	std::cout << "f: " << f->getVal() << std::endl;

	// 多对象(数组)创建
		// 1.直接使用Object[] 模板参数
	TR::shared_ptr<Object[]> sptr1(new Object[3]{11,12,13});
		// 2.使用Object[] 模板参数 + TR中的数组回收方式
	TR::shared_ptr<Object[], TR::MyDeletor<Object[]>> sptr2(new Object[3]{ 21,22,23 });
		// 3.使用Object[] 模板参数 + 指定资源回收方式
	struct Object_deletor {
		void operator()(Object* p) { delete[]p; }
	};
		// 打印,operator[] 的重载
	for (int i = 0; i < 3; i++) std::cout << sptr1[i].getVal() << " ";
	for (int i = 0; i < 3; i++) std::cout << sptr2[i].getVal() << " ";
	std::cout << std::endl;

	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我叫RT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值