cpp智能指针详解+简单模拟实现

本文介绍了在C++中如何避免内存泄漏,通过智能指针(unique_ptr,shared_ptr,weak_ptr)的RAII原理,阐述了它们的工作机制,重点讲解了unique_ptr的简单实现和shared_ptr的引用计数应用,以及weak_ptr用于解决循环引用问题的方法。
摘要由CSDN通过智能技术生成

在cpp中为了避免内存泄漏采取了一系列手段,例如智能指针,智能指针采用RAII思想来管理内存(Resource Acquisition Is Initialization是一种利用对象生命周期来控制程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。)在对象构造时获取资源,接着控制对资源的访问使之在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:
1.不需要显式地释放资源。
2.采用这种方式,对象所需的资源在其生命期内始终保持有效。


在cpp中有三种智能指针供我们使用分别是unique_ptr,shared_ptr,weak_ptr。

1.unique_ptr:

        unique_ptr不允许复制和拷贝(可以移动构造和移动赋值)本质上就是一个unique_ptr管理一个内存空间(如果是多个指针指向同一份内存要用后面的shared_ptr)。

所以在unique_ptr的特性下要实现它的基本功能就十分简单了:

template<typename T>
	class unique_ptr
	{
	public:
		typedef unique_ptr<T> self;
		unique_ptr(T* ptr):_ptr(ptr){}
		~unique_ptr()
		{
			cout << "~unique_ptr()" << endl;
			delete _ptr;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
		unique_ptr(const self& ptr) = delete;
		self& operator=(const self& ptr) = delete;
	private:
		T* _ptr;
	};

2.shared_ptr

        有多个指针指向同一分内存时就要考虑使用shared_ptr了,shared_ptr的本质是采用引用计数的方式来记录有多少个指针指向这份空间,当发生拷贝或赋值时引用计数就++,shared_ptr析构时引用计数就--,只用当引用计数为0时才会释放空间。具体实现如下:

	template<typename T>
	class share_ptr
	{
	public:
		typedef share_ptr<T> self;
		share_ptr(T* ptr = nullptr) :_ptr(ptr) ,_count(new int(1)){}
		~share_ptr()
		{
			relese();
		}
		share_ptr(const self& ptr)
		{
			_count = ptr._count;
			_ptr = ptr._ptr;
			++(*_count);
		}
		int use_count()
		{
			return *_pcount;
		}
		T* get() const
		{
			return _ptr;
		}
		void relese()
		{
			if (--(*_count) == 0)
			{
				delete _count;
				delete _ptr;
				cout << "~share_ptr()" << endl;
			}
		}
		self& operator=(const self& ptr)
		{
//自己给自己赋值时不做改变
//当自身指向内容发生改变时先将原来内容的引用计数--再把新指向内容的引用计数++
			if (ptr._ptr != _ptr)
			{
				relese();
				_ptr = ptr._ptr;
				_count = ptr._count;

				++(*_count);
			}
			return *this;
		}
		T& operator*()
		{
			return *_ptr;
		}
		T* operator->()
		{
			return _ptr;
		}
	private:
		int* _count;//采用指针方式使其所有指向同一块空间的shared_ptr访问同一个计数
		T* _ptr;
	};

实际上shared_ptr有一个坑就是循环引用问题,例如双链表:

struct ListNode
{
//当前节点需要释放就要引用计数为0
//这就要先释放左右两边节点
//但是我本身又指向了左右节点
//要释放左右节点就要先释放我本身
//所以陷入死循环
	typename _val;
	shared_ptr<ListNode> _next;
	shared_ptr<ListNode> _prev;
};

所以cpp引入了weak_ptr来解决该问题。

3.weak_ptr

         它的构造和析构不会引起引用记数的增加或减少同时weak_ptr 没有重载*和->

	template<class T>
	class weak_ptr
	{
	public:
		typedef weak_ptr<T> self;
		weak_ptr()
			:_ptr(nullptr)
		{}

		weak_ptr(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
		}

		self& operator=(const shared_ptr<T>& sp)
		{
			_ptr = sp.get();
			return *this;
		}

	private:
		T* _ptr;
	};

由于它的构造和析构不会引起引用记数的增加或减少所以完美解决了循环引用的问题。

        感谢观看~

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C语言扫地僧

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

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

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

打赏作者

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

抵扣说明:

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

余额充值