智能指针3-----》shared_ptr

shared_ptr是一个引用计数智能指针,用于共享对象的所有权,也就是说它允许多个指针指向同一个对象。这一点与原始指针一致。如下:

#include<iostream>
using namespace std;

class Object
{
private:
	int value;
	Object(const Object&) = delete;
	Object& operator=(const Object&) = delete;
public:
	Object(int x = 0) :value(x) { cout << "creat Object : " << this << endl; };
	~Object() { cout << "destory Object : " << this << endl; };
	int& Value() { return value; }
	const int& Value()const { return value; }
	void Print() const { cout << value << endl; }
};
int main()
{
	shared_ptr<Object> pObj(new Object(100));
	cout << (*pObj).Value() << endl;
	cout << "pObj 引用计数:" << pObj.use_count() << endl;
	shared_ptr<Object> pObj2 = pObj;
	cout << "pObj 引用计数:" << pObj.use_count() << endl;
	cout << "pObj2 引用计数:" << pObj2.use_count() << endl;
	return 0;
}

在这里插入图片描述
如上示例中可以看出:

  • 跟STL里面的容器类型一样,shared_ptr也是模板类,因此在创建share_ptr时需要指定其指向的类型。
  • shared_ptr指针允许多个该类型的指针共享同一个对象。share_ptr使用经典的引用计数的方法来管理对象资源,每个shared_ptr对象关联一个共享的引用计数。
    (当用一个share_ptr初始化另一个share_ptr,或者 将它当作函数传递给一个函数以及作为函数的返回值时,它所关联的引用计数就会递增;当给share_ptr赋予新值或者 销毁一个share_ptr时,计数器就会递减。)
    share_ptr对象的计数器编程0时,它就会自动释放自己所管理的对象。

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

int main()
{
	shared_ptr<string> pStr = make_shared<string>(10, 'a');
	cout << *pStr << endl;
	int* p = new int(10);
	shared_ptr<int> pInt(p);
	cout << *pInt << endl;
	return 0;
}

2、访问所指对象
shared_ptr的使用方法与普通函数指针的使用方法类似,既可以使用解引用操作符*获得原始对象进而访问其各个成员,也可以使用指针访问符->来访问原始对象的各个成员。
3、拷贝与赋值操作
我们可以用一个shared_ptr对象来初始化另一个shared_ptr实例。该操作都会增加其引用计数。
示例:

int main()
{
	shared_ptr<Object> pObj(new Object(100));
	cout << (*pObj).Value() << endl;
	cout << "pObj 引用计数:" << pObj.use_count() << endl;//1
	shared_ptr<Object> pObj2(pObj);
	cout << "pObj 引用计数:" << pObj.use_count() << endl;//2
	cout << "pObj2 引用计数:" << pObj2.use_count() << endl;//2

如果shared_ptr实例p和另一个shared_ptr实例q所指向的类型相同或者可以相互转换,我们还可以进行诸如p=q这样的赋值操作。
该操作会递减p的引用计数,递增q的引用计数值。
示例:

int main()
{
	shared_ptr<Object> pObj1 = make_shared<Object>("a object");
	shared_ptr<Object> pObj2 = make_shared<Object>("b object");

	cout << pObj1.use_count() << endl;
	cout << pObj2.use_count() << endl;
	pObj1 = pObj2;
	cout << pObj1.use_count() << endl;
	cout << pObj2.use_count() << endl;
	cout << pObj1->Value() << endl;
	cout << pObj2->Value() << endl;
}

结果:
在这里插入图片描述
4、检查引用计数
shared_ptr提供了两个函数来检查其共享的引用计数,分别是unique()和use_count().
use_count()函数用来测试当前指针的引用计数值,但是use_count()可能效率旱地,应该只把它用于调试或测试。
unique()函数用来测试该shared_ptr是否是原始指针的唯一拥有者。
5、shared_ptr仿写

#include<iostream>
#include<memory>
using namespace std;
namespace wwn
{
	template<typename T>
	class RefCnt//引用计数
	{
	private:
		T* mPtr;	
		std::atomic<int> mCnt;
	public:	
		RefCnt(T* ptr = nullptr) :mPtr(ptr),mCnt(1){}
		void addRef() { ++mCnt; }
		int delRef() { return --mCnt;}
		int load() { return mCnt.load(); }
		~RefCnt() {}
	};
	template<typename T>
	struct MyDeletor//删除器
	{
		void operator()(T* ptr)const
		{
			if (ptr == nullptr) return;
			delete ptr;
		}
	};
	template<class T,typename Deletor=MyDeletor<T>>
	class shared_ptr
	{
	public:
		typedef T* pointer;
		typedef T  element_type;
		typedef Deletor delete_type;

		delete_type get_deleter()
		{
			return delete_type();
		}
	public:
		shared_ptr(T* ptr = nullptr) : mPtr(ptr)
		{
			mpRefCnt = new RefCnt<T>(mPtr);
		}
		shared_ptr(const shared_ptr<T>& src) :mPtr(src.mPtr), mpRefCnt(src.mpRefCnt)
		{
				mpRefCnt->addRef();
		}
		shared_ptr& operator=(const shared_ptr<T>& src)
		{                                             
			if (src == this)                          
			{                                        
				return *this;
			}
			
			if (0==mpRefCnt->delRef())
			{
				get_deleter()(mPtr);
				delete mpRefCnt;
				mPtr = nullptr;
				mpRefCnt = nullptr;
			}
			mPtr = src.mPtr;
			mpRefCnt = src.mpRefCnt;
			mpRefCnt->addRef();
			return *this;
		}
		~shared_ptr()
		{

			if (0 == mpRefCnt->delRef())
			{
				get_deleter()(mPtr);
				delete mpRefCnt;
			}
			mPtr = nullptr;
			mpRefCnt = nullptr;
		}
		T* get()const { return mPtr; }
		T& operator*()const { return *get(); }
		T* operator->()const { return get(); }
		long use_count() const { return mpRefCnt->load();}
		void reset(T* p = nullptr)
		{
			if (0==mpRefCnt->delRef())
			{
				get_deleter()(mPtr);
				delete mpRefCnt;
			}
			mPtr = p;
			mpRefCnt = new RefCnt<T>(mPtr);
		}
		operator bool()const
		{
			return get() != nullptr;
		}
		bool unique()const
		{
			if (mPtr != nullptr && use_count() == 1)
			{
				return true;
			}
			return false;
		}
	private:
		T* mPtr;
		RefCnt<T>* mpRefCnt;
	};
}

class Object
{
private:
	int value;
	Object(const Object&) = delete;
	Object& operator=(const Object&) = delete;
public:
	Object(int x = 0) :value(x) { cout << "creat Object : " << this << endl; };
	~Object() { cout << "destory Object : " << this << endl; };
	int& Value() { return value; }
	const int& Value()const { return value; }
	void Print() const { cout << value << endl; }
};

int main()
{
	wwn::shared_ptr<Object> pa(new Object(10));
	wwn::shared_ptr<Object> pb(pa);
	cout << pa.use_count() << endl;
	(*pa).Print();
	pa->Print();
	pa->Value() = 100;
	pa->Print();
	pb->Print();
	return 0;
}

6、shared_ptr 的线程安全

  • shared_ptr的引用计数本身是线程安全(引用计数是原子操作)。
  • 多个线程同时读同一个shared_ptr对象是线程安全的。
  • 如果是多个线程对同一个shared_ptr进行读和写,则需要加锁。
  • 多线程读写shared_ptr所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的,也需要加锁保护。(因为shared_ptr有两个数据成员,读写操作不能原子化,使得多线程读写同一个shared_ptr对象需要加锁。)

7、为什么要尽量使用make_shared()来申请管理对象以及引用计数的内存;调用适当的构造函数初始化对象;返回一个shared_ptr。
为了节省一次内存分配。
shared_ptr obj(new Object(10)):需要为Object和RefCnt各分配一次内存,现在用make_shared()的话,可以一次分配一块足够大的内存,供Object和RefCnt对象容身。不过Object的构造函数所需的参数要传给make_shared(),后者再传给Object::Object(),这只有在C++11里通过perfect forwarding才能完美解决。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值