在编程中,我们经常会涉及到对象的操作,而经常的操作模式如下图所示:创建对象->使用对象->销毁对象。
我们提供的服务有:成都网站建设、成都做网站、微信公众号开发、网站优化、网站认证、城步ssl等。为上1000家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的城步网站制作公司
而这个对象有可能创建的时候会需要构建很多资源,消耗比较大, 比如:在hiredis的SDK中每次都创建一个redisContext,如果需要查询,那就首先要进行网络连接。如果一直都是上图的工作方式,那将会频繁的创建连接,查询完毕后再释放连接。重新建立连接,让网络的查询效率降低。
这个时候就可以构建一个对象池来重复利用这个对象,并且一般要做到线程安全:
那么符合如下条件的,应该适合使用对象池技术:
首先介绍一下程序的样例对象Object, 其就接受一个初始化参数strInit。
class Object { public: Object(std::string strInit) : m_strInit(strInit) { std::cout << "Object()" << std::endl; } virtual ~Object() { std::cout << "~Object()" << std::endl; } private: std::string m_strInit; };
先来看看对象池的类图:
然后再来看看代码吧:
class ObjectPool { public: ObjectPool() { ; } ~ObjectPool() { ; } std::shared_ptr GetObject(std::string strInit) { std::shared_ptr pObject; { std::lock_guard guard(m_mutex); if (!m_lObjects.empty()) { pObject = m_lObjects.front(); m_lObjects.pop_front(); } } if (!pObject) { pObject = std::make_shared(strInit); } return pObject; } void ReturnObject(std::shared_ptr pObject) { if (!pObject) return; std::lock_guard guard(m_mutex); m_lObjects.push_front(pObject); } private: std::mutex m_mutex; std::list> m_lObjects; }; 那么使用起来比较简单,如下所示。 ObjectPool objPool; auto pObj1 = objPool.GetObject("abc"); //操作对象完成任务 //...... objPool.ReturnObject(pObj1); 但是要注意一点,有时候可能使用完了,却忘记调用ReturnObject了,这个时候是否想起了RAII技术《C++ RAII实现golang的defer》和《从lock_guard来说一说C++常用的RAII》。那么问一问,可以实现一个自动回收的对象池吗?不需要调用者在对象使用完成后,手动将对象归还给对象池,并且你可能要问: 针对不同类型的Object,是不是可以用模板去实现更加通用的实现一个对象池 构造函数的参数列表,也可以是任意的形式 自动回收的对象池 要实现自动回收的对象池,首先要了解unique_ptr和shared_ptr都可以自定义删除器,也就是说,比如当从对象池获取到的对象是用智能指针包裹的,一般默认的删除器为delete,那我们可以自义定删除器为: 将这个对象重新放回到对象池. 代码如下: template class ObjectPool { public: ObjectPool() { m_fObjDeleter = [&](T* pObj) { if (m_bDeconstruct) delete pObj; else { std::lock_guard guard(m_mutex); m_lObjects.push_front(std::shared_ptr(pObj, m_fObjDeleter)); } }; } ~ObjectPool() { m_bDeconstruct = true; } template std::shared_ptr GetObject(Args&&... args) { std::shared_ptr pObject; { std::lock_guard guard(m_mutex); if (!m_lObjects.empty()) { pObject = m_lObjects.front(); m_lObjects.pop_front(); } } if (!pObject) { pObject.reset(new T(std::forward(args)...), m_fObjDeleter); } return pObject; } void ReturnObject(std::shared_ptr pObject) { if (!pObject) return; std::lock_guard guard(m_mutex); m_lObjects.push_front(pObject); } private: std::function m_fObjDeleter; std::mutex m_mutex; std::list> m_lObjects; volatile bool m_bDeconstruct = false; }; 自动回收 关于自动回收,这个涉及到一个问题,是用unique_ptr还是shared_ptr呢,在这篇大牛写的文章中进行了比较详细的阐述《thinking in object pool》(链接见参考部分), 说明了应该使用unique_ptr,也看到不少人在网上转发。主要如下阐述:因为我们需要把智能指针的默认删除器改为自定义删除器,用shared_ptr会很不方便,因为你无法直接将shared_ptr的删除器修改为自定义删除器,虽然你可以通过重新创建一个新对象,把原对象拷贝过来的做法来实现,但是这样做效率比较低。而unique_ptr由于是独占语义,提供了一种简便的方法方法可以实现修改删除器,所以用unique_ptr是最适合的。…这种方式需要每次都创建一个新对象,并且拷贝原来的对象,是一种比较低效的做法。但本人自己进行了思考,认为可以做到使用shared_ptr一样实现了高效的自动回收机制。首先定义了一个m_fObjDeleter自定义deleter, 不过这种做法可能比较难理解一些,就是定义的m_fObjDeleter函数内也会调用m_fObjDeleter。当shared_ptr引用计数为0的时候,会做如下事情: 如果发现是OjbectPool调用了析构函数,则直接释放对象 如果发现OjbectPool并没有调用析构函数,则将对象放入对象池中 m_fObjDeleter = [&](T* pObj) { if (m_bDeconstruct) delete pObj; else { std::lock_guard guard(m_mutex); m_lObjects.push_front(std::shared_ptr(pObj, m_fObjDeleter)); } }; 当创建对象的时候指定自定义的deleter: pObject.reset(new T(std::forward(args)...), m_fObjDeleter); 模板支持 使用了模板可以支持通用的对象: template class ObjectPool { public: //...... template std::shared_ptr GetObject(Args&&... args) { //...... } void ReturnObject(std::shared_ptr pObject) { //...... } private: std::function m_fObjDeleter; //..... std::list> m_lObjects; //....... }; 可变函数参数完美转发 不同的对象,可能使用的构造函数参数也不同,那么当调用GetObject的时候的参数要设置为可变参数,其实现如下: template std::shared_ptr GetObject(Args&&... args) { std::shared_ptr pObject; { std::lock_guard guard(m_mutex); if (!m_lObjects.empty()) { pObject = m_lObjects.front(); m_lObjects.pop_front(); } } if (!pObject) { pObject.reset(new T(std::forward(args)...), m_fObjDeleter); } return pObject; } 其他 以上对对象池的基本内容进行了阐述,那么对于对象池的实现要根据场景还有若干的细节,有些还比较重要: 是否要在启动的时候初始化指定数量的对象? 对象池的数量是否要设置一个上限或者下线 对象池重复利用,当取出来后要注意,是不是要对对象做一次reset之类的操作,防止对象上一次的调用残留数据对本地调用构成影响,这个要根据自己对象的特点去进行相应的reset操作 有时候当这个对象可能出现了特别的情况需要销毁,是否也需要考虑到? 等等 参考 <>模板部分 << thinking in object pool >>: https://www.cnblogs.com/qicosmos/p/4995248.html 网页标题:对象池的使用场景以及自动回收技术 URL网址:http://www.shufengxianlan.com/qtweb/news3/406303.html 网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等 广告 声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联 猜你还喜欢下面的内容 夸克软件是正规软件吗 全民k歌为什么不能关闭 深入了解Linux光纤卡属性,优化系统性能(linux光纤卡属性) 什么可以查对方黑名单 PE工具如何正确装Linux系统 (pe下如何装linux系统安装) 防火墙技术如何保障网络安全?防火墙的局限是什么? 金甬高铁2023年几月通车?宁波双线服务器托管 继电器如何打开盖 浅析大数据安全与传统数据保护的差异 品牌网站制作知识 学会这十一个SEO优化技巧,掌控SEO优化套路 关于三个SASE的理解误区 PolarDB是不是优先列存效果更好? 利用Redis管理信息,极大提升效率(redis管理信息系统) 服务器有没有免费试用?(免费服务器一天试用) Redis还是Kafka选择哪种中间件(redis还是kafka) word文档行间距怎么调成一致的?(段落行间距怎么设置,怎么设置行间距) redhat有什么收费限制?(redhat收费标准) phpmvc控制器如何实现 极限国度怎么更改服装?windows7玩家国度开始菜单 论Web2.0时代的PHP:优点还是问题? 红帽向亚太区的系统集成商推出OpenShiftPracticeBuilder计划 香港服务器:安全可靠,为您的业务护航 IIS入门:抵御攻击的IIS硬化 打不开网站说解析不生效-域名及账户问题 分类信息网站 服务器租用 公路钻孔机 玻璃贴膜 活动板房 工商代办 格栅板 混凝土搅拌站 资质代办 玻璃钢雕塑 垃圾桶 VR全景 搬家公司 凿毛机 服务器托管 花箱 墙体彩绘 服务器托管 网站改版 成都路面机械设备 成都网站建设报价 四川雅安服务器托管 彭山网站制作 手机网站制作 成都工装公司 梓潼做网站 成都酒店服定制 成都钢筋机械设备 做手机网站 网站推广优化 水泥基自流平 成都口碑营销公司 网站排名优化 网络口碑营销 成都棕树机房 钢筋机械设备 四川成都网站制作
那么使用起来比较简单,如下所示。
ObjectPool objPool; auto pObj1 = objPool.GetObject("abc"); //操作对象完成任务 //...... objPool.ReturnObject(pObj1);
但是要注意一点,有时候可能使用完了,却忘记调用ReturnObject了,这个时候是否想起了RAII技术《C++ RAII实现golang的defer》和《从lock_guard来说一说C++常用的RAII》。
那么问一问,可以实现一个自动回收的对象池吗?不需要调用者在对象使用完成后,手动将对象归还给对象池,并且你可能要问:
要实现自动回收的对象池,首先要了解unique_ptr和shared_ptr都可以自定义删除器,也就是说,比如当从对象池获取到的对象是用智能指针包裹的,一般默认的删除器为delete,那我们可以自义定删除器为: 将这个对象重新放回到对象池. 代码如下:
template class ObjectPool { public: ObjectPool() { m_fObjDeleter = [&](T* pObj) { if (m_bDeconstruct) delete pObj; else { std::lock_guard guard(m_mutex); m_lObjects.push_front(std::shared_ptr(pObj, m_fObjDeleter)); } }; } ~ObjectPool() { m_bDeconstruct = true; } template std::shared_ptr GetObject(Args&&... args) { std::shared_ptr pObject; { std::lock_guard guard(m_mutex); if (!m_lObjects.empty()) { pObject = m_lObjects.front(); m_lObjects.pop_front(); } } if (!pObject) { pObject.reset(new T(std::forward(args)...), m_fObjDeleter); } return pObject; } void ReturnObject(std::shared_ptr pObject) { if (!pObject) return; std::lock_guard guard(m_mutex); m_lObjects.push_front(pObject); } private: std::function m_fObjDeleter; std::mutex m_mutex; std::list> m_lObjects; volatile bool m_bDeconstruct = false; };
关于自动回收,这个涉及到一个问题,是用unique_ptr还是shared_ptr呢,在这篇大牛写的文章中进行了比较详细的阐述《thinking in object pool》(链接见参考部分), 说明了应该使用unique_ptr,也看到不少人在网上转发。主要如下阐述:
因为我们需要把智能指针的默认删除器改为自定义删除器,用shared_ptr会很不方便,因为你无法直接将shared_ptr的删除器修改为自定义删除器,虽然你可以通过重新创建一个新对象,把原对象拷贝过来的做法来实现,但是这样做效率比较低。而unique_ptr由于是独占语义,提供了一种简便的方法方法可以实现修改删除器,所以用unique_ptr是最适合的。
…
这种方式需要每次都创建一个新对象,并且拷贝原来的对象,是一种比较低效的做法。
但本人自己进行了思考,认为可以做到使用shared_ptr一样实现了高效的自动回收机制。首先定义了一个m_fObjDeleter自定义deleter, 不过这种做法可能比较难理解一些,就是定义的m_fObjDeleter函数内也会调用m_fObjDeleter。当shared_ptr引用计数为0的时候,会做如下事情:
m_fObjDeleter = [&](T* pObj) { if (m_bDeconstruct) delete pObj; else { std::lock_guard guard(m_mutex); m_lObjects.push_front(std::shared_ptr(pObj, m_fObjDeleter)); } };
当创建对象的时候指定自定义的deleter:
pObject.reset(new T(std::forward(args)...), m_fObjDeleter);
使用了模板可以支持通用的对象:
template class ObjectPool { public: //...... template std::shared_ptr GetObject(Args&&... args) { //...... } void ReturnObject(std::shared_ptr pObject) { //...... } private: std::function m_fObjDeleter; //..... std::list> m_lObjects; //....... };
不同的对象,可能使用的构造函数参数也不同,那么当调用GetObject的时候的参数要设置为可变参数,其实现如下:
template std::shared_ptr GetObject(Args&&... args) { std::shared_ptr pObject; { std::lock_guard guard(m_mutex); if (!m_lObjects.empty()) { pObject = m_lObjects.front(); m_lObjects.pop_front(); } } if (!pObject) { pObject.reset(new T(std::forward(args)...), m_fObjDeleter); } return pObject; }
以上对对象池的基本内容进行了阐述,那么对于对象池的实现要根据场景还有若干的细节,有些还比较重要:
参考
网页标题:对象池的使用场景以及自动回收技术 URL网址:http://www.shufengxianlan.com/qtweb/news3/406303.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
广告
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联
猜你还喜欢下面的内容
品牌网站制作知识
分类信息网站