C++11智能指针--shared_ptr

一、shared_ptr的分析和使用

        做出一个像java中的垃圾回收器,并且可以运用到所有资源,Heap内存和系统资源都可以使用的系统。

        std::shared_ptr就是C++11为了达到上述目标推出的方式。

        shared_ptr实现了共享所有权方式来管理资源对象,这意味没有一个特定shared_ptr拥有资源对象。相反,这些指向同一个资源对象的std::shared_ptr相互协作来确保该资源对象在不需要的时候被析构。

1、特点:

(1)基于共享所有权模式:多个指针能够同时指向同一个资源。

(2)基于共享所有权,使用引用计数控制块管理资源对象的生命周期。

(3)提供拷贝构造函数和赋值重载函数;提供移动构造函数和移动赋值函数。

(4)为了实现单个对象和一组对象的管理,添加了删除器类型。

(5)在容器保存shared_ptr对象是安全。

(6)shared_ptr重载了operator->和operator*运算符,因此它可以像普通指针一样使用。

2、引用计数器的作用:

(1)当新的shared_ptr对象与资源对象的地址关联时,则在其构造函数中,将与此资源对象关联的引用计数加1.

(2)当任何shared_ptr对象超出作用域时,则在其析构函数中,将与资源对象关联的引用计数减1.如果引用计数变为0,则表示没有其他shared_ptr对象与此资源对象关联,在这种情况下,它使用deleter删除器删除该资源对象。

3、创建shared_ptr实例:

        最安全和高效的方法是调用make_shared库函数,该函数会在堆中分配一个对象并初始化,最后返回指向此对象的shared_ptr实例。如果你不想使用make_shared,也可以先明确new出一个对象,然后把其原始指针传递给shared_ptr的构造函数。

#include<iostream>
#include<memory>
using namespace std;

class Int
{
private:
	int value;
public:
	Int(int x = 0) :value(x)
	{
		cout << "Create Int:" << endl;
	}
	~Int()
	{
		cout << "Destroy Int" << endl;
	}
	void PrintInt()const
	{
		cout << value << endl;
	}
	int& Value() { return value; }
	/*const int& Value()const
	{
		return value;
	}*/
};
int main()
{
	/*Int* ip = new Int(10);
	std::shared_ptr<Int> pInta(ip);
	std::shared_ptr<Int> pIntb(ip);
	pInta.get()->PrintInt();
	return 0;*/
	std::shared_ptr<Int> pInta(new Int(10));
	std::shared_ptr<Int> pIntc;
	pInta.get()->PrintInt();
	cout << "pInta引用计数:" << pInta.use_count() << endl;
	std::shared_ptr<Int> pIntb(pInta);
	cout << "pInta引用计数:" << pInta.use_count() << endl;
	cout << "pIntb引用计数:" << pIntb.use_count() << endl;
	pIntb->Value() += 100;
	pIntb->PrintInt();
	pInta->PrintInt();
	return 0;

}

从上面这段代码中,我们对shared_ptr指针有一些直观的了解。

        一方面,跟STL中大多数容器类型一样,shared_ptr也是模版类,因此在创建shared_ptr时需要指定其指向的类型。另一方面,正如其名一样,shared_ptr指针允许让多个该类型的指针共享同一堆分配对象。同时shared_ptr使用经典的“引用计数”方法来管理对象资源,每个shared_ptr对象关联一个共享的引用计数。

        对于shared_ptr在拷贝和赋值时的行为是,每个shared_ptr都有一个关联的计数值,通常称为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。

        当我们给shared_ptr赋予一个新值或是shared_ptr被销毁(例如一个局部的shared_ptr离开其作用域)时,计数器就会递减。

        shared_ptr对象的计数器变为0,它就会自动释放自己所管理的对象。

       

4、shared_ptr代码仿写

#include<iostream>
#include<atomic>
#include<memory>
using namespace std;

//删除器
template<typename _Ty>
class My_Deletor
{
public:
	void operator()(_Ty* ptr)const
	{
		delete ptr;
	}
};
//特化版本
template<typename _Ty>
class My_Deletor<_Ty[]>
{
public:
	void operator()(_Ty* ptr)const
	{
		delete[]ptr;
	}
};

//计数器
template<typename _Ty>
class My_RefCount
{
public:
	typedef _Ty element_type;
	typedef _Ty* pointer;
private:
	_Ty* _Ptr;
	std::atomic<int> _Uses;//shared
	std::atomic<int> _Weaks;//weak_ptr
public:
	My_RefCount(_Ty* ptr = nullptr) :_Ptr(ptr), _Uses(0)
	{
		if (_Ptr != nullptr)
		{
			_Uses = 1;
		}
	}
	~My_RefCount() { }
	void Incref()
	{
		++_Uses;
	}
	void Incwref()
	{
		++_Weaks;
	}
	int Decref()
	{
		return --_Uses;
	}
	int Decwref()
	{
		return --_Weaks;
	}
	int _Use_count()const
	{
		return static_cast<int>(_Uses);
	}
};

template<class _Ty,class Deleter=My_Deletor<_Ty>>
class My_shared_ptr
{
private:
	_Ty* mPtr;
	My_RefCount<_Ty>* mRef;
	Deleter mDeleter;
public:
	My_shared_ptr(_Ty* ptr = nullptr) :mPtr(ptr), mRep(nullptr)
	{
		if (mPtr != nullptr)
		{
			mRef = new My_RefCount<T>(mPtr);
		}
	}
	~My_shared_ptr()
	{
		if (0 == mRef->Decref())
		{
			mDeleter(mPtr);
			delete mRef;
		}
	}
	My_shared_ptr(const My_shared_ptr& src) :mPtr(src.mPtr), mRef(src.mRef)
	{
		if (mPtr != nullptr)
		{
			mRef->Incref();
		}
	}
	My_shared_ptr& operator=(const My_shared_ptr& src)
	{
		if (this == &src || this->mPtr == src.mPtr)
		{
			return *this;
		}
		if (0 == this->mRef->Decref())
		{
			mDeleter(mPtr);
			delete mRef;
		}
		mPtr = src.mPtr;
		mRef = src.mRef;
		if (mPtr != nullptr)
		{
			mRef->Incref();
		}
		return *this;
	}
	int use_count()const
	{
		return mRef != nullptr ? mRef->_Use_count() : 0;
	}

	element_type* get()const
	{
		return _Ptr;
	}
	void swap(My_shared_ptr* _Other)
	{
		std::swap(mPtr, _Other->mPtr);
		std::swap(mRef, _Other->mRef);
	}
	void reset()
	{
		if (mPtr != nullptr && 0 == mRef->Decref())
		{
			mDeleter(mPtr);
			delete mRef;
		}
	}
	void reset(_Ty* p)
	{
		if (p == nullptr)
		{
			reset();
			return;
		}
		if (mPtr != nullptr && 0 == mRef->Decref())
		{
			mDeleter(mPtr);
			delete mRef;
		}
		if (mPtr != nullptr)
		{
			mRef = new My_RefCount<T>(mPtr);
		}
	}
	explicit operator bool()const
	{
		return get() != nullptr;
	}
	_Ty& operator*()const
	{
		return *get();
	}
	_Ty* operator->()const
	{
		return get();
	}
	bool owner_before(const My_shared_ptr& _Right)const
	{
		return mRef < _Right.mRef;
	}

	//移动构造和移动赋值
	My_shared_ptr(My_shared_ptr&& _Right)
	{
		mPtr = _Right.mPtr;
		mRef = _Right.mRef;
		_Right.mPtr = nullptr;
		_Right.mRef = nullptr;
	}
	My_shared_ptr& operator=(My_shared_ptr&& _Right)
	{
		if (this == &_Right)
		{
			return *this;
		}
		My_shared_ptr(move(_Right)).swap(*this);
		return *this;
	}
};

5、辅助函数

(1)get返回指向被管理对象的指针;

(2)reset替换被管理对象;

(3)shared_ptr不提供release释放被管理对象的所有权的函数;

(4)swap交换被管理对象;

(5)operator bool()const 检查是否有关联的管理对象;

(6)重载operator*,operator->,访问被管理对象;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值