C++【智能指针】

智能指针的作用:

堆内存的申请和释放都由程序员自己管理。

普通指针:需要程序员手动释放,容易造成内存泄漏(比如忘记手动释放,或者程序异常)和二次释放的问题。

智能指针:程序结束自己释放,不需要程序员手动释放。所以不存在内存泄漏

智能指针其实就是利用一种叫做RAII(资源获取即初始化)的技术对普通指针进行封装。所以智能指针的实质是个对象(模板类)

智能指针的作用是防止忘记调用delete释放内存和程序异常没有delete,或者多次释放了同一个指针。

智能指针底层代码实现【没考虑线程安全的】

#include<stdio.h>
#include<iostream>
#include<list>
using namespace std;

class ResList
{
public:
	// 给ptr资源增加引用计数
	void addRef(void *ptr)
	{
		list<Node>::iterator it1 = nodelist.begin();
		while (it1 != nodelist.end())
		{
			if (it1->_resptr == ptr)
			{
				it1->_count++;																						
			}
			++it1;
		}
		nodelist.push_back(Node(ptr));
	}
	// 给ptr资源减少引用计数
	int delRef(void *ptr)
	{
		list<Node>::iterator it1 = nodelist.begin();
		while (it1 != nodelist.end())
		{
			if (it1->_resptr == ptr)
			{
				if (it1->_count == 1)		//只有最后一个指针时,析构
				{
					nodelist.erase(it1);
					return 0;
				}
				else		//还有好多指针指向一个资源,指针数减一
				{
					it1->_count--;
					return it1->_count;
				}
			}
			++it1;
		}
		return -1;
	}

private:
	struct Node
	{
		Node(void *ptr = NULL)
		:_resptr(ptr), _count(1){}
		void *_resptr;	//资源
		int _count;		//指针数
	};
	list<Node> nodelist;
};

template<typename T>
class CSmartPtr
{
public:
	CSmartPtr(T*ptr = NULL) :mptr(ptr)
	{
		if (mptr != NULL)
			reslist.addRef(ptr);
	}
	CSmartPtr(const CSmartPtr<T> &src) :mptr(src.mptr)
	{
		if (mptr != NULL)
			reslist.addRef(mptr);
	}
	CSmartPtr<T>& operator=(const CSmartPtr<T> &src)
	{
		if (this == &src)
			return *this;

		if (reslist.delRef(mptr) == 0)
		{
			delete mptr;
		}

		mptr = src.mptr;
		reslist.addRef(mptr);
		return *this;
	}
	~CSmartPtr()
	{
		if (reslist.delRef(mptr) == 0)
		{
			delete mptr;
		}
	}
	T& operator*(){ return *mptr; }
	T* operator->(){ return mptr; }

private:
	T*mptr;
	static ResList reslist;
};
template<typename T>
ResList CSmartPtr<T>::reslist;

智能指针的循环/交叉引用问题

class A
{
public:
   shared_ptr<B> _ptrb;
}
class B
{
public:
   shared_ptr<A> _ptra;
}

shared_ptr<A> ptra(new A());
shared_ptr<B> ptrb(new B());

//循环引用
ptra->_ptrb = ptrb;
ptrb->_ptra = ptra;

此问题发生的原因是:强智能指针会改变资源引用计数,在循环引用的时候,引用计数被多加了一次。所以该析构的时候,引用计数还为1,则不进行析构操作

解决方法:在创建对象的地方使用强智能指针,其他地方一律使用弱智能指针(因为弱智能指针不能改变资源的引用计数

弱智能指针不能访问对象的方法,要访问对象,就需要转换为强智能指针

弱智能指针提升为强智能指针的方法:

shared_ptr<A> ptra = _ptra.lock();

if(ptra != NULL)    //判断是否为NULL,从而判断是否提升成功。当提升成功后,资源的引用计数随即加一

{

     ptra -> func();

}

库里面提供的智能指针 

头文件:#include<memory>

不带引用计数的智能指针===》会发生浅拷贝

auto_ptr  -- 会将原来的auto_ptr置空,只有最新的auto_ptr才能访问资源(就是一块资源只能一个指针访问,释放旧指针)

因为会释放旧的指针,所以我们禁止使用该指针 

scope_ptr

unique_ptr          --- 与shared_ptr不同,unique_ptr拥有它所指向的对象,在某一时刻,只能有一个unique_ptr指向特定的对象。当unique_ptr被销毁时,它所指向的对象也会被销毁。因此不允许多个unique_ptr指向同一个对象,所以不允许拷贝与赋值。

带引用计数的智能指针

shared_ptr    强智能指针【可改变资源的引用计数】,是线程安全的

weak_ptr     弱智能指针【不能改变资源的引用计数】

没有重载operator*和->,它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况

相关资料:

C++11中智能指针的原理、使用、实现
C++面试题(四)——智能指针的原理和实现

unique_ptr的使用和陷阱: https://blog.csdn.net/qq_33266987/article/details/78784286

猜你喜欢

转载自blog.csdn.net/qq_42212982/article/details/83582945