• 首页
  • 做网站
  • 做推广
  • 做电商
  • 成功案例
  • 服务支持
  • 解决方案
  • 关于中企
控制台
登录
退出
注册会员
数字门户
通用版
全行业全场景的企业建站
内贸营销版
自动化营销网站
全球营销版
企业海外获客的外贸网站
个性化场景定制服务
安全稳定.高性价比.个性化定制网站
行业解决方案版
数字门户·行业解决方案版
AI友好性服务
与AI共生,帮助企业建立AI可信身份
推荐购买
企业域名
迈入互联网的第一步
企业邮箱
随时随地,全球畅邮
视觉设计类
VR全景 | 图片拍摄 | 视频制作
网站安全类
SSL证书 | 等保认证
成功案例
核心必备
全球SEO
以内容建立长效获客路径
百度首屏展位
优质流量独享,抢占百度首屏位置
Yandex推广
东欧市场获客利器
Google海外推广
外贸必备,出海利器
推荐购买
一站式企业出海
让全球客户主动找上门
成功案例
核心必备
全网商城
全渠道在线做生意
移动商城
网上开店不操心
推荐购买
零售行业OMO解决方案
电商全场景实现流量聚合变现, 用户沉淀复购
全场景电商电商解决方案
商城周边应用
粉丝分销、社区团购、活动营销等营销工具
成功案例
帮助中心
数字门户产品服务保障 服务中心 设计师 信息化讲堂 常见服务问题
实战应用
产品剖析 律所应用场景·案例分析 律所行业专家 行业解读
中企商学院
直播课 学员中心 学员升级 中企讲师
学习中心
电商运营学院 网站建设学院
企业通用
企业安全等保解决方案 企业全景展示解决方案 品牌数字化营销解决方案 品牌零售数字商业解决方案 开拓型外贸企业解决方案 成长型外贸企业解决方案 网站AI友好性解决方案
行业应用
一站式企业出海解决方案 智慧园区解决方案 零售行业OMO解决方案 B2B电商平台建设解决方案 数字化政务门户解决方案
行业解决方案
行业白皮书
企业概况
关于我们 企业文化 发展历程 数码庄园 法律隐私 FAQ
资质荣誉
企业资质 所获荣誉
新闻中心
热点资讯 行业活动
联系我们
联系我们 全国网点 工作机会
形状
  • 域名
  • 产品
  • 热点
  • 案例
  • 文章
  • 帮助中心
  • 课程
建站域名包含 .com、.cn、.net三款后缀
形状 搜索
建站推荐后缀
自选后缀 (0)
确定
选择您要查询的域名后缀:
登录 注册 退出
    首页
  • 做网站
  • 做推广
  • 做电商
  • 成功案例 资讯热点
  • 服务支持
  • 应用与服务
  • 关于中企
  • 中企商学院
查看更多
核心必备
数字门户 内贸营销版
全球营销版 行业解决方案版
通用版 企业域名
企业邮箱
行业应用
外贸客户洞察 平台产品导入
数字名片
视觉设计
VR全景 视频制作
图片拍摄
网络安全
等保认证 SSL证书
查看更多
核心必备
全球SEO 百度首屏展位
Yandex推广 Google海外推广
解决方案
外贸推广解决方案
查看更多
核心必备
全网商城 移动商城
装修服务
电商产品拍摄
解决方案
零售行业OMO解决方案 政府采购电商平台解决方案
查看更多
查看更多
查看更多
帮助中心
数字门户产品服务保障 服务中心
设计师 信息化讲堂
解决方案
外贸数字营销解决方案 企业视频直播解决方案
企业安全等保解决方案 品牌数字化营销解决方案
品牌零售数字商业解决方案 智慧园区解决方案
B2B电商平台建设解决方案 数字化政务门户解决方案
开拓型外贸企业解决方案 成长型外贸企业解决方案
行业解决方案
实战应用
产品剖析 律所行业专家
行业解读
学习中心
电商运营学院 网站建设学院
查看更多
应用与服务
VR智能全景 个性化场景定制服务
网站安全服务 云定制
企业视频直播 Banner设计
产品主图设计 图片处理
查看更多
企业概况
关于我们 企业文化
发展历程 数码庄园
法律隐私
资质荣誉
企业资质 所获荣誉
新闻中心
新闻公告 媒体报道
社会公益 视频中心
行业资讯
联系我们
联系我们 工作机会
查看更多
查看更多
网站首页 网站建设 IT知识 IT知识教程 详解C++中shared_ptr的使用教程

详解C++中shared_ptr的使用教程

2021-05-02 21:12:26

shared_ptr是一种智能指针(smart pointer)。shared_ptr的作用有如同指针,但会记录有多少个shared_ptrs共同指向一个对象。
这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。这在非环形数据结构中防止资源泄露很有帮助。
auto_ptr由于它的破坏性复制语义,无法满足标准容器对元素的要求,因而不能放在标准容器中;如果我们希望当容器析构时能自动把它容纳的指针元素所指的对象删除时,通常采用一些间接的方式来实现,显得比较繁琐。boost库中提供了一种新型的智能指针shared_ptr,它解决了在多个指针间共享对象所有权的问题,同时也满足容器对元素的要求,因而可以安全地放入容器中。

总结下几个使用shared_ptr需要注意的问题:

一. 相互引用链

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 class C; class B : public std::enable_shared_from_this<B> { public: ~B(){ cout << "~B" << endl; } void SetPC(std::shared_ptr<C>& pc){ _pc = pc; } private: std::shared_ptr<C> _pc; }; class C : public std::enable_shared_from_this<C> { public: ~C(){ cout << "~C" << endl; } void SetPB(std::shared_ptr<B>& pb){ _pb = pb; } private: std::shared_ptr<B> _pb; }; int main() { std::shared_ptr<C> pc = std::make_shared<C>(); std::shared_ptr<B> pb = std::make_shared<B>(); pc->SetPB(pb); pb->SetPC(pc); return 0; }

上面的代码中,B和C均不能正确析构,正确的做法是,在B和C的释放函数,如Close中,将其包含的shared_ptr置空。这样才能解开引用链。

二. 自引用
还有个比较有意思的例子:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class C : public std::enable_shared_from_this < C > { public: ~C() { std::cout << "~C" << std::endl; } int32_t Decode(const char* data, size_t) { return 0; } void SetDecoder(std::function<int32_t(const char*, size_t)> decoder) { _decoder = decoder; } private: std::function<int32_t(const char*, size_t)> _decoder; }; int main() { { std::shared_ptr<C> pc = std::make_shared<C>(); auto decoder = std::bind(&C::Decode, pc, std::placeholders::_1, std::placeholders::_2); pc->SetDecoder(decoder); } // C不能正确析构 因为存在自引用 return 0; }

上面的C类包含了一个function,该function通过std::bind引用了一个std::shared_ptr,所以_decoder其实包含了一个对shared_ptr的引用。导致C自引用了自身,不能正确析构。需要在C的Close之类的执行关闭函数中,将_decoder=nullptr,以解开这种自引用。

三. 类中传递
下面的例子中有个更为隐蔽的问题:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Session : public std::enable_shared_from_this < Session > { public: ~Session() { std::cout << "~C" << std::endl; } void Start() { // 进行一些异步调用 // 如 _socket.async_connect(..., boost::bind(&Session::ConnectCompleted, this), boost::asio::placeholders::error, ...) } void ConnectCompleted(const boost::system::err_code& err) { if(err) return; // ... 进行处理 // 如 _socket.async_read(..., boost::bind(&Session::ReadCompleted, this), boost::asio::placeholders::error, ...) } void Session::ReadComplete(const boost::system::error_code& err, size_t bytes_transferred) { if (err || bytes_transferred == 0) { DisConnect(); return; } // 处理数据 继续读 // ProcessData(); // _socket.async_read(...) } private: std::function<int32_t(const char*, size_t)> _decoder; }; int main() { { std::shared_ptr<Session> pc = std::make_shared<Session>(); pc->Start(); } return 0; }

上面Session,在调用Start时,调用了异步函数,并回调自身,如果在回调函数的 boost::bind 中 传入的是shared_from_this(),那么并无问题,shared_ptr将被一直传递下去,在网络处理正常时,Session将正常运行,即使main函数中已经没有它的引用,但是它靠boost::bind”活了下来”,boost::bind会保存传给它的shared_ptr,在调用函数时传入。当网络遇到错误时,函数直接返回。此时不再有新的bind为其”续命”。Session将被析构。
而真正的问题在于,如果在整个bind链中,直接传递了this指针而不是shared_from_this(),那么实际上当函数执行完成后,Session即会析构,包括其内部的资源(如 _socket)也会被释放。那么当boost底层去执行网络IO时,自然会遇到错误,并且仍然会”正常”回调到对应函数,如ReadCompleted,然后在err中告诉你:”由本地系统终止网络连接”(或:”An attempt to abort the evaluation failed. The process is now in an indeterminate state.” )。让人误以为是网络问题,很难调试。而事实上此时整个对象都已经被释放掉了。
注:由于C++对象模型实现所致,成员函数和普通函数的主要区别如下:

  • 成员函数带隐式this参数
  • 成员函数具有访问作用域,并且函数内会对非静态成员变量访问做一些转换,如 _member_data 转换成 this->_member_data;

也就是说,成员函数并不属于对象,非静态数据成员才属于对象。

因此如下调用在编译期是合法的:

? 1 ((A*)nullptr)->Func();

而如果成员函数A::Func()没有访问A的非静态成员变量,这段代码甚至能正确运行,如:

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Test { public: void Say() { std::cout << "Say Test" << std::endl; } void Set(int data) { _data = data; } private: int _data; }; int main() { // 运行成功 ((Test*)nullptr)->Say(); // 运行会崩掉,尝试访问空指针所指内存(_data) ((Test*)nullptr)->Set(1); return 0; }

正因为这种特性,有时候在成员函数中纠结半天,也不会注意到这个对象已经”不正常了”,被释放掉了。

四. shared_ptr 使用总结
尽量不要环引用或自引用,可通过weak_ptr来避免环引用:owner持有child的shared_ptr child持有owner的weak_ptr
如果存在环引用或自引用,记得在释放时解开这个引用链
对于通过智能指针管理的类,在类中通过shared_from_this()而不是this来传递本身
在类释放时,尽量手动置空其所有的shared_ptr成员,包括function

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。 如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章

C++智能指针shared_ptr分析
C++智能指针shared_ptr分析概要:shared_ptr是c++智能指针中适用场景多,功能实现较多的智能指针。它采取引用计数的方法来实现释放指针所指向的
C++11新特性之智能指针(shared_ptr/unique_ptr/weak_ptr)
shared_ptr基本用法shared_ptr采用引用计数的方式管理所指向的对象。当有一个新的shared_ptr指向同一个对象时(复制shared_ptr等
C++开发:为什么多线程读写shared_ptr要加锁的详细介绍
我在《Linux多线程服务端编程:使用muduoC++网络库》第1.9节“再论shared_ptr的线程安全”中写道:(shared_ptr)的引用计数本身是安
c++11 新特性——智能指针使用详解
c++11添加了新的智能指针,unique_ptr、shared_ptr和weak_ptr,同时也将auto_ptr置为废弃(deprecated)。但是在实际
shared_ptr线程安全性全面分析
正如《STL源码剖析》所讲,“源码之前,了无秘密”。本文基于shared_ptr的源代码,提取了shared_ptr的类图和对象图,然后分析了shared_pt

最新文章

载入进度条 效果
邮件发送简单例子-html文件
详解关于html,css,js三者的加载顺序问题
限制复选框的最大可选数
随鼠标上下滚动的jquery代码

hot 热门文章

python模拟登陆Tom邮箱示例分享
苹果11抖音怎么投屏? iphone将投影投屏到电视的技巧
蚂蚁森林节气签怎么领
华为mate30怎么更新系统?华为mate30更新手机系统教程
小米电视怎么下载斗鱼

猜你喜欢

JavaScript 命名空间 使用介绍
javascript ���名规则 变量命名规则
javascript 秒表计时器实现代码
Javascript 面向对象之重载
JavaScript 面向对象之命名空间
以上产品还未完全满足我的所有需求,在下方提交我的专属需求
我的专属需求:
*手机号:
*验证码:
img
咨询报价
现在咨询

Copyright © 1999-2026 中企动力科技股份有限公司(300.cn)All Rights Reserved

京公网安备11030102010293号 京ICP证010249-2

代理域名注册服务机构:中网瑞吉思(天津)科技有限公司 北京新网数码信息技术有限公司

域名注册服务机构许可证编号:京D3-20220007

中企动力域名投诉处理:400-660-5555-9 service4006@300.cn

中国互联网络信息中心(受理范围:“.CN”和“.中国”域名)投诉处理 010-58813000  service@cnnic.cn

立即联系我

立即提交
  • 7 x 24
    全国售后支持
  • 100 倍
    故障时长赔付
  • 27 年
    27年行业服务经验
  • 70 家
    全国售后支持
  • 1600+ 名
    超千人的设计、研发团队
  • 150 万
    服务企业客户150万家
联系我们| 意见反馈| 全国网点| 站点地图| 行业站| 邮箱登录| English| 中企集团官网
Copyright © 1999-2026 中企动力科技股份有限公司(300.cn)版权所有 京公网安备11030102010293号 京ICP证010249-2
代理域名注册服务机构:中网瑞吉思(天津)科技有限公司 北京新网数码信息技术有限公司
域名注册服务机构许可证编号:京D3-20220007
中企动力域名投诉处理:400-660-5555-9 service4006@300.cn
中国互联网络信息中心(受理范围:“.CN”和“.中国”域名)投诉处理 010-58813000  service@cnnic.cn
售后服务:400-660-5555-1
img

在线咨询

建站在线咨询

img

获取方案

获取建站报价/方案

我们联系您img

img

微信咨询

扫一扫添加
动力姐姐微信

img
img

TOP

我们尽快联系您