智能指针!

智能指针

干什么用的?

将智能指针封装成类,利用类对象释放时调用析构函数的特点,将资源交给智能指针管理

利用对象生命周期控制资源——RAII

如何过渡到下面这个问题的?

智能指针的拷贝,默认是浅拷贝,即多个智能指针会指向同一份资源。这是没有问题的,符合智能指针的定义

这样做的问题是,同份资源会被多次析构

为了解决智能指针拷贝(拷贝构造、赋值拷贝)导致的多次析构的问题,衍生出了如下3种智能指针

auto_ptr  1

任何时候只允许一个智能指针对象对一份资源做管理

模拟实现auto_ptr

	template<class T>
	class auto_ptr {
	public:
		//构造
		auto_ptr(T* ptr=nullptr):_ptr(ptr){}
		//拷贝构造
		auto_ptr(auto_ptr<T>& ap)
		{
			_ptr = ap._ptr;
			ap._ptr = nullptr;
		}
		//赋值拷贝 需要考虑特殊情况
		auto_ptr& operator=(auto_ptr& ap)
		{
			delete _ptr;
			_ptr = ap._ptr;
			ap._ptr = nullptr;
			return *this;
		}
		//析构函数
		~auto_ptr()
		{
			if (_ptr != nullptr)
			{
				delete _ptr;
				_ptr = nullptr;
			}

		}
		//->
		T* operator->()
		{
			return _ptr;
		}
		//*
		T& operator* ()
		{
			return *_ptr;
		}
	private:
		T* _ptr;
	};
}

int* a =nullptr;

delete a 为什么不会报错

因为 C++ 标准规定对空指针进行删除操作时,会忽略这个操作,不会引发运行时错误。

int b=0;

int *a =&b

delete a 为什么会报错

因为delete是用于释放new出来的堆空间(动态分配出来的空间),而a指向的空间属于栈上的空间

比较拷贝构造与赋值拷贝之间的差异

为什么要delete _ptr?

因为一个auto_ptr对象只能管理一个资源,所以要先释放自身管理的资源

为什么要这样做?

因为一个资源只能被一个auto_ptr对象管理。

为什么不delete ap._ptr,因为该auto_ptr还有可能被赋值

特殊情况考虑

2个auto_ptr对象的_ptr都为nullptr(表明这两个对象没有管理任何资源)

就会出现delete nullptr的情况,所以要在构造函数部分加判空判断

int* a =nullptr;

delete a 为什么不会报错

因为 C++ 标准规定对空指针进行删除操作时,会忽略这个操作,不会引发运行时错误。

int b=0;

int *a =&b

delete a 为什么会报错

因为delete是用于释放new出来的堆空间(动态分配出来的空间),而a指向的空间属于栈上的空间

为什么拷贝构造没有delete _ptr

因为管理资源的对象还没有被创建出来,也就是说该对象还没有管理任何资源

总结:拷贝构造与赋值拷贝

相同点就是:它们都要保证一个资源只能被一个对象管理

不同点就是:拷贝构造是一个已存在的对象拷贝给一个尚未存在的对象,所以不用释放

                      赋值拷贝是两个已存在的对象间的拷贝,所以要释放

unique_ptr 0

防拷贝,也就是说该智能指针禁止拷贝

具体就是将拷贝构造与赋值构造这两个函数禁用

template <class T>
	class unique_ptr {
	public:
		//默认构造 表示没有管理任何资源
		unique_ptr(T* ptr = nullptr) :_ptr(ptr) {}
		//析构函数
		~unique_ptr()
		{
			if (_ptr != nullptr)
			{
				delete _ptr;
				_ptr = nullptr;
			}

		}
		//->
		T* operator->()
		{
			return _ptr;
		}
		//*
		T& operator* ()
		{
			return *_ptr;
		}
		unique_ptr(unique_ptr<T>& up) = delete;
		unique_ptr& operator=(unique_ptr<T>& up) = delete;
	private:
		T* _ptr;
	};

shared_ptr  >1

允许拷贝,利用计数器管理使用同一份资源的智能指针,当计数器等于0时才释放智能指针管理的资源

这意味着什么?

这意味着可以有多个shared_ptr对象管理同一份资源

	template<class T>
	class shared_ptr {
	public:
		//构造
		shared_ptr(T* ptr=nullptr):_ptr(ptr),_pcount(new int(1)){}
		//拷贝构造
		shared_ptr(shared_ptr& sp)
		{
			_ptr = sp._ptr;
			_pcount = sp._pcount;
			*_pcount++;
		}
		//赋值构造
		shared_ptr& operator=(shared_ptr& sp)
		{
			if (sp._ptr != _ptr)
			{
				if (-- ( * _pcount) == 0)
				{
					delete _ptr;
					delete _pcount;
				}
				_ptr = sp._ptr;
				_pcount = sp._pcount;
				(* _pcount)++;
			}
			return *this;
		}
		//析构
		~shared_ptr()
		{
			if (--(*_pcount) == 0)
			{
				if (_ptr != nullptr)//特殊情况,_ptr有可能指向空,就对他做处理
				{
					delete _ptr;
					_ptr = nullptr;
				}
				delete _pcount;
				_pcount = nullptr;
			}
		}
		//->
		T* operator->()
		{
			return _ptr;
		}
		//*
		T& operator* ()
		{
			return *_ptr;
		}
		//引用计数
		int use_count()
		{
			return *(_pcount);
		}
	private:
		T* _ptr;
		int* _pcount;
	};
}

循环引用问题

shared_ptr存在循环引用问题,如下例

将ListNode交给shared_ptr管理

运行结果  没有如预期结果释放资源

 原因:

程序运行时

程序 结束后

为什么shared_ptr<ListNode>_next 与shared_ptr<ListNode>_prev不在程序结束的时候释放呢?因为它们是new出来的,需要手动释放

weak_ptr

解决循环引用

上述问题的关键其实就是多了一个shared_ptr,导致程序结束时计数器不为0

weak_ptr 接受一个shared_ptr对象 但是计数器不+1

实现:

	template<class T>
	class weak_ptr {
	public:
		//构造
		weak_ptr(T* ptr=nullptr):_ptr(ptr){}
		//拷贝构造
		weak_ptr(shared_ptr<T>& sp)
		{
			if(sp.use_count!=0)
			_ptr = sp.get();
		}
		//赋值拷贝
		weak_ptr& operator=(shared_ptr<T>& sp)
		{
			if (sp.use_count() != 0)
			{
				_ptr = sp.get();
			}
			return *this;
		}
		//析构
		~weak_ptr()
		{
			_ptr = nullptr;
		}
		//->
		T* operator->()
		{
			return _ptr;
		}
		//*
		T& operator* ()
		{
			return *_ptr;
		}
	private:
		T* _ptr;
	};
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值