智能指针(二)—— unique_ptr、shared_ptr 的简单模拟实现

智能指针其实就是资源管理权限的转移,自己不想手动释放,交给一个对象管理,对象什么时候被销毁,这块资源也就什么时候被释放。unique_ptr 、shared_ptr 和weak_ptr 之间的区别如下: 

  • unique_ptr:字面意思是独一无二的指针。这种智能指针只允许有一个管理者,其底层做了禁止拷贝的相关工作。
  • shared_ptr:字面意思是共享的指针。这种智能指针允许多个管理者,底层通过引用计数实现
  • weak_ptr:严格来说不是指针,一般出现在一些特殊场景,用于解决shared_ptr 循环拷贝的问题。

         目录

1、unique_ptr

2、shared_ptr

(1) 成员变量:_ptr、_refCount

(2) 构造函数:初始化引用计数

(3)  拷贝构造:引用计数自增

(4) 析构函数:引用计数自减

(5) 完整代码以及改进方向


1、unique_ptr

unique_ptr 只允许有一个管理者,既然管理权限交到了自己手里,就不允许其他智能指针插手。其核心在于防拷贝机制。

实现起来也比较简单,如果只是防止类外拷贝,我们只需要将拷贝构造函数放到 private修饰的作用域内即可;但是如果要同时防止类外和类内拷贝,我们可以使用delete关键字,具体使用如下:

template<class T>
class UniquePtr
{
public:
	UniquePtr(T* ptr) 
		:_ptr(ptr)          // 获取资源
	{}
	~UniquePtr() {
		if (_ptr)
		{
			delete _ptr;    //  释放资源
			_ptr = nullptr;
		}
	}
​
    UniquePtr(const UniquePtr<T>& up) = delete;                  // 禁止拷贝构造
    UniquePtr<T>& operator=(const UniquePtr<T>& up) = delete;    // 禁止赋值构造
private:
	T* _ptr;
};

2、shared_ptr

shared_ptr 允许有多个管理者来同时管理这份资源。实现时为了避免资源被重复释放,实际采用的是引用计数来达到资源共享,每次析构只是让引用计数自减,当引用计数自减为 0 的时候,再释放资源.

(1) 成员变量:_ptr、_refCount

需要注意的是,_refCount 的类型是int*,因为如果存在多个管理者,不光是资源要共享,引用计数也要共享。如果_refCount的类型是int,那么不同对象会各自持一份_refCount的拷贝版本,计数时无法同步。

template<class T>
class SharedPtr
{
private:
	T* _ptr;                // 保存资源的地址
	int* _refCount;         // 引用计数
};

(2) 构造函数:初始化引用计数

除了获取资源的地址外,我们要将引用计数初始化为1,因为最初的资源管理者产生了。

SharedPtr(T* ptr)
	:_ptr(ptr),
	_refCount(new int(1))
{}

(3)  拷贝构造:引用计数自增

每发生一次拷贝构造,说明有新的管理者要参与资源管理,此时引用计数自增

SharedPtr(const SharedPtr<T>& sp)
 	:_ptr(sp._ptr),
	_refCount(sp._refCount)
{
	(*_refCount) ++;
}

(4) 析构函数:引用计数自减

每有一个管理者被销毁,引用计数就要自减;一旦引用计数为0,说明管理者不存在了,为了防止内存泄漏,此时需要释放资源。

~SharedPtr() {
	if (--(*_refCount)==0 && _ptr)
	{
		delete _ptr;
		_ptr = nullptr;
	}
}

(5) 完整代码以及改进方向

这段代码仅用于了解 shared_ptr 的基本逻辑,实际上,如果要继续优化,引用计数是临界资源,引用计数自增或自减时需要加锁控制。

template<class T>
class SharedPtr
{
public:
	SharedPtr(T* ptr)
		:_ptr(ptr),
		_refCount(new int(1))
	{
        cout << "引用计数: " << *_refCount << endl;
    }

	SharedPtr(const SharedPtr<T>& sp)
	 	:_ptr(sp._ptr),
		_refCount(sp._refCount)
	{
		(*_refCount) ++;
        cout << "引用计数: " << *_refCount << endl;
	}

	~SharedPtr() {
		if (--(*_refCount)==0 && _ptr)
		{
			delete _ptr;
			_ptr = nullptr;
		}
	}

private:
	T* _ptr;
	int* _refCount;
};

简单测试的结果如下:

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值