智能指针的使用和模拟实现

1.智能指针的使用和模拟实现

1.1RALL

RALL:是一种利用对象生命周期来控制程序资源的简单技术

在对象构造的时候获取资源,接着控制对资源的访问之在对象生命周期期间内始终保持有效,最后在对象析构的时候释放资源,这样做的好处有两个

1.不需要显示的释放内存

2.采用这种方式,对象所需的资源在生命周期内始终有效

举个例子(抛出异常无法释放内存)

template<class T>
class Smartptr
{
public:
	Smartptr(T* ptr = nullptr)
		:_ptr(ptr)
	{
	}
	~Smartptr()
	{
		if (_ptr)
		{
			delete _ptr;
			cout << "delete[] "<< endl;
		}
	}

private:
	T* _ptr;
};

double Division(int a, int b)
{
	if (b == 0)
		throw "Division by zero condition!";
	else
		return ((double)a / (double)b);
}

void Func()
{
	int* array = new int[10];
	memset(array, 0, sizeof(int)* 10);
	Smartptr<int> s(array);
	int len, time;
	cin >> len >> time;
	cout << Division(len, time) << endl;
}
int main()
{
	try
	{
		Func();
	}
	catch (const char* errmsg)
	{
		cout << errmsg << endl;
	}

	system("pause");
	return 0;
}
1.2只能指针的原理

上述的SmartPtr还不能将其称为智能指针,因为它不具有指针的行为,所以必须重载解引用和->访问空间所指的内容才构成智能指针。

即在SmartPtr类中重载:

T& operator*(){

​ return *_ptr;

}

T operator->(){

​ return _ptr;

}

1.3std::auto_ptr(C++98)

c++98库中提供的auto_ptr智能指针当其拷贝后就把元对象的指针悬空了,再通过原指着真访问资源时就会出现问题,所以这种指针不提倡使用。

1.4std::unique_ptr

c++11中提供了更靠谱的unique_ptr

unique_ptr的设计思路简单粗暴就是防止拷贝,下面模拟实现一下它的原理:

template <class T>

class Unique_Ptr

{

public:

	Unique_Ptr(T* ptr)

		:_ptr(ptr)

	{}

	~Unique_Ptr()

	{

		if(_ptr)

		{

			delete _ptr;

			_ptr = nullptr;

		}

	}

	//重载*  ->

	T& operator*()

	{

		return *_ptr;

	}

	T* operator->()

	{

		return _ptr;

	}

private:

	Unique_Ptr(const Unique_Ptr<T>& up);

	Unique_Ptr<T>& operator=(const Unique_ptr<T>& up);

	\*Unique_Ptr(const Unique_Ptr<T>& up)  = delete;

	Unique_Ptr<T>& operator=(const Unique_ptr<T>& up) = delete;*/



	T* _ptr;

}
1.5std::share_ptr

C++11中开始提供更靠谱的并且支持拷贝的shared_ptr

share_ptr的基本原理就是::是通过引用计数的方式来实现多个shared_ptr对象之间共享资源。

  1. shared_ptr在其内部,给每个资源都维护了着一份计数,用来记录该份资源被几个对象共享。
  2. 在对象被销毁时(也就是析构函数调用),就说明自己不使用该资源了,对象的引用计数减一。
  3. 如果引用计数是0,就说明自己是最后一个使用该资源的对象,必须释放该资源;
  4. 如果不是0,就说明除了自己还有其他对象在使用该份资源,不能释放该资源,否则其他对象就成野指 针了。

模拟实现share_ptr如下:

template <class T>
class Share_Ptr
{
public:
	//构造函数在第一次申请资源后调用
	Share_Ptr(T* ptr)
		:_ptr(ptr)
		,Use_Count(new int(1))
		, _mtx(new mutex)
	{}
	Share_Ptr(const Share_Ptr<T>& sp)
		:_ptr(sp._ptr)
		, Use_Count(sp.Use_Count)
		, _mtx(sp._mtx)
	{
		//当前指向资源的引用计数加1
		addRef();
	}
	Share_Ptr<T>& operator=(const Share_Ptr<T>& sp)
	{
		//对于两个智能指针管理同一片空间的情况,不需要进行赋值
		if (_ptr != sp._ptr){
			if (subRef() == 0)
			{
				delete _ptr;
				delete Use_Count;
				delete _mtx;
			}
			_ptr = sp._ptr;
			Use_Count = sp.Use_Count;
			_mtx = sp._mtx;
			addRef();
		}
		return this;
	}
	int addRef()
	{
		_mtx->lock();
		++(*Use_Count);
		_mtx->unlock();
		return *Use_Count;
	}
	int subRef()
	{
		_mtx->lock();
		--(*Use_Count);
		_mtx->unlock();
		return *Use_Count;
	}
	~Share_Ptr()
	{
		if (subRef() == 0)
		{
			if (_ptr)
			{
				delete _ptr;
				_ptr = nullptr;
				delete _mtx;
				_mtx = nullptr;
				delete Use_Count;
				Use_Count = nullptr;
			}
		}
	}
	//重载* ->
	T& operator*()
	{
		return *_ptr;
	}
	T* operator->()
	{
		return _ptr;
	}
	int UseCount()
	{
		return *Use_Count;
	}
private:
	T* _ptr;
	int* Use_Count;
	//加锁,给一个全局的锁代价太大
	mutex* _mtx;
};
struct Date
{
	int _year;
	int _month;
	int _day;
	~Date()
	{
		cout << "~Date()" << endl;
	}
};
void Fun(const Share_Ptr<Date>& sp,int n)
{
	for (int i = 0; i < n; i++)
		Share_Ptr<Date> spcopy(sp);
}
int main()
{
	Share_Ptr<Date> sp(new Date);
	//Share_Ptr<Date> sp1(sp);
	int n = 100000;
	thread t1(Fun, sp, n);
	thread t2(Fun, sp, n);
	t1.join();
	t2.join();
	cout << sp.UseCount() << endl;
	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值