智能指针3-----》shared_ptr
发布日期:2021-05-07 09:16:11 浏览次数:24 分类:精选文章

本文共 5306 字,大约阅读时间需要 17 分钟。

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

#include
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
pObj(new Object(100)); cout << (*pObj).Value() << endl; cout << "pObj 引用计数:" << pObj.use_count() << endl; shared_ptr 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
pStr = make_shared
(10, 'a'); cout << *pStr << endl; int* p = new int(10); shared_ptr
pInt(p); cout << *pInt << endl; return 0;}

2、访问所指对象

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

int main(){   	shared_ptr pObj(new Object(100));	cout << (*pObj).Value() << endl;	cout << "pObj 引用计数:" << pObj.use_count() << endl;//1	shared_ptr 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 pObj1 = make_shared("a object");	shared_ptr pObj2 = make_shared("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
#include
using namespace std;namespace wwn{ template
class RefCnt//引用计数 { private: T* mPtr; std::atomic
mCnt; public: RefCnt(T* ptr = nullptr) :mPtr(ptr),mCnt(1){ } void addRef() { ++mCnt; } int delRef() { return --mCnt;} int load() { return mCnt.load(); } ~RefCnt() { } }; template
struct MyDeletor//删除器 { void operator()(T* ptr)const { if (ptr == nullptr) return; delete ptr; } }; template
> 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
(mPtr); } shared_ptr(const shared_ptr
& src) :mPtr(src.mPtr), mpRefCnt(src.mpRefCnt) { mpRefCnt->addRef(); } shared_ptr& operator=(const shared_ptr
& 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
(mPtr); } operator bool()const { return get() != nullptr; } bool unique()const { if (mPtr != nullptr && use_count() == 1) { return true; } return false; } private: T* mPtr; RefCnt
* 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
pa(new Object(10)); wwn::shared_ptr 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才能完美解决。。

上一篇:如何启用 BitLocker 网络解锁
下一篇:智能指针2-----》unique_ptr

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2025年04月03日 05时56分22秒