
智能指针3-----》shared_ptr
4、检查引用计数 shared_ptr提供了两个函数来检查其共享的引用计数,分别是unique()和use_count(). use_count()函数用来测试当前指针的引用计数值,但是use_count()可能效率旱地,应该只把它用于调试或测试。 unique()函数用来测试该shared_ptr是否是原始指针的唯一拥有者。 5、shared_ptr仿写
发布日期:2021-05-07 09:16:11
浏览次数:24
分类:精选文章
本文共 5306 字,大约阅读时间需要 17 分钟。
shared_ptr是一个引用计数智能指针,用于共享对象的所有权,也就是说它允许多个指针指向同一个对象。这一点与原始指针一致。如下:
#includeusing 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
- 跟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_ptrpStr = 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_ptrpObj(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_ptrpObj1 = 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;}
结果:

#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才能完美解决。。发表评论
最新留言
逛到本站,mark一下
[***.202.152.39]2025年04月03日 05时56分22秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
IDEA 调试Java代码的两个技巧
2019-03-06
Spring AOP 面向切面编程之AOP是什么
2019-03-06
MyBatis常见面试题:#{}和${}的区别是什么?
2019-03-06
Vue 数组和对象更新,但视图未更新,背后的故事
2019-03-06
剑指Offer面试题:9.二进制中1的个数
2019-03-06
《你是在做牛做马还是在做主管》- 读书笔记
2019-03-06
ASP.NET Core on K8S学习之旅(12)Ingress
2019-03-06
重新温习软件设计之路(4)
2019-03-06
《刷新》:拥抱同理心,建立成长型思维
2019-03-06
MVC3+NHibernate项目实战(二) :数据库访问层
2019-03-06
Flask入门
2019-03-06
MySQL数据库与python交互
2019-03-06
python如何对字符串进行html转义与反转义?
2019-03-06
开发小白也毫无压力的hexo静态博客建站全攻略 - 躺坑后亲诉心路历程
2019-03-06
java例题_24 逆向输入数字
2019-03-06
不管人生怎么走,都需要实时回头看看
2019-03-06