当前位置: 首页 > 编程日记 > 正文

share_ptr_c++11

C++智能指针 shared_ptr
  shared_ptr 是一个标准的共享所有权的智能指针, 允许多个指针指向同一个对象. 定义在 memory 文件中(非memory.h), 命名空间为 std.

std::shared_ptr<int> sp1 = std::make_shared<int>(10);
std::shared_ptr<std::string> sp2 = std::make_shared<std::string>("Hello c++");
auto sp4 = std::make_shared<std::string>("c++11");
printf("sp4=%s\n", (*sp4).c_str());

1.use_count 返回引用计数的个数
2.unique 返回是否是独占所有权( use_count 为 1)
3.swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
4.reset 放弃内部对象的所有权或拥有对象的变更, 会引起原有对象的引用计数的减少
5.get 返回内部对象(指针), 由于已经重载了()方法, 因此和直接使用对象是一样的.如 shared_ptr<int> sp(new int(1)); sp 与 sp.get()是等价的


std::shared_ptr<int> sp0(new int(2));
std::shared_ptr<int> sp1(new int(11));
std::shared_ptr<int> sp2 = sp1;
printf("%d\n", *sp0);               // 2
printf("%d\n", *sp1);               // 11
printf("%d\n", *sp2);               // 11
sp1.swap(sp0);
printf("%d\n", *sp0);               // 11
printf("%d\n", *sp1);               // 2
printf("%d\n", *sp2);               // 11

std::shared_ptr<int> sp3(new int(22));
std::shared_ptr<int> sp4 = sp3;
printf("%d\n", *sp3);               // 22
printf("%d\n", *sp4);               // 22
sp3.reset();                       
printf("%d\n", sp3.use_count());    // 0
printf("%d\n", sp4.use_count());    // 1
printf("%d\n", sp3);                // 0
printf("%d\n", sp4);                // 指向所拥有对象的地址
           
std::shared_ptr<int> sp5(new int(22));
std::shared_ptr<int> sp6 = sp5;
std::shared_ptr<int> sp7 = sp5;
printf("%d\n", *sp5);               // 22
printf("%d\n", *sp6);               // 22
printf("%d\n", *sp7);               // 22
printf("%d\n", sp5.use_count());    // 3
printf("%d\n", sp6.use_count());    // 3
printf("%d\n", sp7.use_count());    // 3
sp5.reset(new int(33));                       
printf("%d\n", sp5.use_count());    // 1
printf("%d\n", sp6.use_count());    // 2
printf("%d\n", sp7.use_count());    // 2
printf("%d\n", *sp5);               // 33
printf("%d\n", *sp6);               // 22
printf("%d\n", *sp7);               // 22

shared_ptr 的赋值构造函数和拷贝构造函数:
auto r = std::make_shared<int>(); // r的指向的对象只有一个引用, 其 use_count == 1
auto q = r; // r指向的对象的引用计数加1, 此时 q 与 r 指向同一个对象, 并且其引用计数相同, 都为原来的值加1.


使用 shared_ptr 的注意事项
(1) shared_ptr 作为被保护的对象的成员时, 小心因循环引用造成无法释放资源.
假设 a 对象中含有一个 shared_ptr<CB> 指向 b 对象, b 对象中含有一个 shared_ptr<CA> 指向 a 对象, 并且 a, b 对象都是堆中分配的
考虑对象 b 中的 m_spa 是我们能最后一个看到 a 对象的共享智能指针, 其 use_count 为2, 因为对象 b 中持有 a 的指针, 所以当 m_spa 说再见时,
m_spa 只是把 a 对象的 use_count 改成1; 对象 a 同理; 然后就失去了 a,b 对象的联系.
解决此方法是使用 weak_ptr 替换 shared_ptr . 以下为错误用法, 导致相互引用, 最后无法释放对象

运行下述代码会发现 CA, CB 析构函数都不会打印. 因为他们都没有释放内存.
class CB;
            class CA;

class CA
            {
            public:
                CA(){}
                ~CA(){PRINT_FUN();}

void Register(const std::shared_ptr<CB>& sp)
                {
                    m_sp = sp;
                }

private:
                std::shared_ptr<CB> m_sp;
            };

class CB
            {
            public:
                CB(){};
                ~CB(){PRINT_FUN();};

void Register(const std::shared_ptr<CA>& sp)
                {
                    m_sp = sp;
                }

private:
                std::shared_ptr<CA> m_sp;
            };

std::shared_ptr<CA> spa(new CA);
            std::shared_ptr<CB> spb(new CB);

spb->Register(spa);
            spa->Register(spb);
            printf("%d\n", spb.use_count()); // 2
            printf("%d\n", spa.use_count()); // 2


(2) 小心对象内部生成 shared_ptr
class Y : public std::enable_shared_from_this<Y>
{
public:
       std::shared_ptr<Y> GetSharePtr()
       {
            return shared_from_this();
        }
};


对普通的类(没有继承 enable_shared_from_this) T 的 shared_ptr<T> p(new T). p 作为栈对象占8个字节,为了记录( new T )对象的引用计数, p 会在堆上分配 16 个字节以保存引用计数等“智能信息”.
    share_ptr 没有“嵌入(intrusive)”到T对象, 或者说T对象对 share_ptr 毫不知情.
    而 Y 对象则不同, Y 对象已经被“嵌入”了一些 share_ptr 相关的信息, 目的是为了找到“全局性”的那16字节的本对象的“智能信息”.
考虑下面的代码:
            Y y;
            std::shared_ptr<Y> spy = y.GetSharePtr(); // 错误, y 根本不是 new 创建的
            Y* y = new Y;
            std::shared_ptr<Y> spy = y->GetSharePtr(); // 错误, 问题依旧存在, 程序直接崩溃
        正确用法:
            std::shared_ptr<Y> spy(new Y);
            std::shared_ptr<Y> p = spy->GetSharePtr();
            printf("%d\n", p.use_count()); // 2

(3) 小心多线程对引用计数的影响
首先, 如果是轻量级的锁, 比如 InterLockIncrement 等, 对程序影响不大; 如果是重量级的锁, 就要考虑因为 share_ptr 维护引用计数而造成的上下文切换开销.
其次, 多线程同时对 shared_ptr 读写时, 行为不确定, 因为shared_ptr本身有两个成员px,pi. 多线程同时对 px 读写要出问题, 与一个 int 的全局变量多线程读写会出问题的原因一样.
(4) 与 weak_ptr 一起工作时, weak_ptr 在使用前需要检查合法性
std::weak_ptr<A> wp;
        {
            std::shared_ptr<A>  sp(new A);  //sp.use_count()==1
            wp = sp; //wp不会改变引用计数,所以sp.use_count()==1
            std::shared_ptr<A> sp2 = wp.lock(); //wp没有重载->操作符。只能这样取所指向的对象
        }
        printf("expired:%d\n", wp.expired()); // 1
        std::shared_ptr<A> sp_null = wp.lock(); //sp_null .use_count()==0;

(5) shared_ptr 不支持数组, 如果使用数组, 需要自定义删除器, 如下是一个利用 lambda 实现的删除器:
      std::shared_ptr<int> sps(new int[10], [](int *p){delete[] p;});

对于数组元素的访问, 需使要使用 get 方法取得内部元素的地址后, 再加上偏移量取得. 
for (size_t i = 0; i < 10; i++)
            {
                *((int*)sps.get() + i) = 10 - i;
            }

for (size_t i = 0; i < 10; i++)
            {
                printf("%d -- %d\n", i, *((int*)sps.get() + i));
            }

转载于:https://www.cnblogs.com/henryliublog/p/9055562.html

相关文章:

【Python】ubuntu14安装pycaffe环境:python2.7及依赖库

1、问题描述 ubuntu14自带的python2.7版本是python2.7.5&#xff0c;安装pycaffe环境时&#xff0c;出现错误&#xff0c;提示版本低。在bing上搜索源码安装python2.7.16的步骤&#xff0c;后续使用时&#xff0c;又报错&#xff0c;缺少SLL模块&#xff1a; Cant connect to…

周志华、张潼亲自辅导AI课程,DeeCamp 2019正式启动

4 月 8 日&#xff0c;创新工场对外宣布 DeeCamp 2019 人工智能训练营正式启动。 据介绍&#xff0c;DeeCamp 2019 将于 7 月 15 日至 8 月 23 日在北京、上海、南京、广州四地同时举办。今年招生规模也将扩大&#xff0c;计划招收 600 名大学生&#xff0c;进行为期 5 周的理…

No.2 条件

2019独角兽企业重金招聘Python工程师标准>>> clojure中不仅有if 还有when 还有什么when-do when-first when-let 一堆 首先介绍if (defn if? [x](if (pos? x)x(- x))) 这事一个取绝对值的方法,方法名改了下,pos? 是判断是否为正数 参数只能为数字 能看明白吧…

如何用Python和BERT做中文文本二元分类?| 程序员硬核评测

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」全日程揭晓&#xff0c;请扫码咨询 ↑↑↑作者 | 王树义来源 | 王树芝兰&#xff08;ID:nkwangshuyi&#xff09;兴奋去年&#xff0c; Google 的 BERT 模型一发布出来&#xff0c;我就很兴奋。因为我当时正在用 fast.ai 的…

【C++】Google Protocol Buffer(protobuf)详解(二)

代码走读&#xff1a;caffe中protobuf的详细使用过程 【一】proto文件&#xff0c;以caffe.proto中BlobShape为例 syntax "proto2"; //指明protobuf版本&#xff0c;默认是v2&#xff0c;其它版本&#xff1a;"proto3"package caffe; // 最终生成c代码…

Linux使用

软件操作 软件包管理 yum安装 yum install ...卸载 yum remove ...搜索 yum serach ...清理缓存 yum clean packages列出已安装 yum list软件包信息 yum info ...硬件资源信息 内存free -m 硬盘df -h 负载&#xff08;w或top&#xff09;w 12:53:49 up 2:33, 3 users, load ave…

通过进程ID获得该进程主窗口的句柄

一个进程可以拥有很多主窗口&#xff0c;也可以不拥有主窗口&#xff0c;所以这样的函数是不存在的&#xff0c;所幸的是&#xff0c;相反的函数是有的。所以我们可以调用EnumWindows来判断所有的窗口是否属于这个进程。 typedef struct tagWNDINFO{  DWORD dwProcessId;  …

【AI】caffe源码分析(一)

【一】caffe依赖开源库 【C】google gflags详解 【C】google glog详解 【C】Google Protocol Buffer&#xff08;protobuf&#xff09;详解&#xff08;一&#xff09; 【C】Google Protocol Buffer&#xff08;protobuf&#xff09;详解&#xff08;二&#xff09; 【C】goog…

专访博世王红星:大数据和AI将是中国制造业升级新动力

数据分析挖掘与工业大数据是智能制造与工业互联网的核心&#xff0c;其本质是通过促进数据的自动流动与智能决策去解决控制和业务问题&#xff0c;有效减少决策过程所带来的不确定性&#xff0c;并尽量克服人工决策的缺点&#xff0c;从而推动智能制造进程与智能工厂的建设&…

C进阶 - 内存四驱模型

一.内存四驱模型 不知我们是否有读过 《深入理解 java 虚拟机》这本书&#xff0c;强烈推荐读一下。在 java 中我们将运行时数据&#xff0c;分为五个区域分别是&#xff1a;程序计数器&#xff0c;java 虚拟机栈&#xff0c;本地方法栈&#xff0c;java 堆&#xff0c;方法区。…

ATEN—第十章OSPF的高级配置(4)

实验使用的工具&#xff1a;小凡模拟器一、在路由器R1上&#xff0c;配置接口&#xff0c;启动ospf路由进程和rip,宣告网段&#xff0c;并配置路由重分发★☆R1☆★☆→Router>Router>enableRouter#config terminalRouter(config)#hostname R1-jinR1-jin(config)#interfa…

【ubuntu】ubuntu14.04、16.04、18.04 LTS版本支持时间

0、历史版本下载地址 http://old-releases.ubuntu.com/releases/ http://mirrors.163.com/ubuntu-releases/ 1、官网说明 https://wiki.ubuntu.com/Kernel/LTSEnablementStack 2、简要记录 如下图&#xff1a; 14.04.0(v3.13) 14.04.1(v3.13) 14.04.5(v4.4) LTS 支持至 20…

BERT拿下最佳长论文奖!NAACL 2019最佳论文奖公布

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」全日程揭晓&#xff0c;请扫码咨询 ↑↑↑作者 | 刘静编辑 | 李尔客本文经授权转自公众号图灵Topia&#xff08;ID&#xff1a;turingtopia&#xff09;今日&#xff0c;自然语言处理顶会NAACL 2019最佳论文奖公布&#xff…

Git Bash修改默认路径

Git Bash默认安装在C:/user目录下&#xff0c;如果管理其他目录的代码库&#xff0c;需要切换目录。 修改Git Bash的默认路径&#xff0c;不需要每次切换了。 方法&#xff1a; 桌面Git Bash快捷方式&#xff0c;右键-->属性-->“快捷方式”标签 1&#xff0c;修改“起止…

NextGEN Gallery ~ 最强WordPress相册插件

博客照片很多&#xff1f;上传和管理图片太烦&#xff1f;想幻灯显示相册&#xff1f;在博客中任意插入动态图片效果&#xff1f;…… 你和我一样&#xff0c;需要NextGEN Gallery&#xff0c;最强WordPress相册插件&#xff01; 其实网上可以搜到不少关于这个插件的介绍&#…

【经验】网络加速:pip

一、python pip下载加速 参考博客&#xff1a;让PIP源使用国内镜像&#xff0c;提升下载速度和安装成功率。 pip/anaconda修改镜像源&#xff0c;加快python模块安装速度 1、Linux下 修改 ~/.pip/pip.conf (没有就创建一个文件夹及文件。文件夹要加“.”&#xff0c;表示是隐…

iframe 有那些缺

*iframe 会阻塞主页面的 Onload 事 *iframe 和主页面共享连接池&#xff0c;而浏览器对相同域的连接有限制(6-8前)&#xff0c;所以会影响页面的并行加 使用 iframe 之前需要考虑这两个缺点。如果需要使用 iframe&#xff0c;最通过 javascrit 动态给 iframe 添加 src 属性值&a…

用Python让蔡徐坤在我的命令行里打篮球!|附完整代码

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」全日程揭晓&#xff0c;请扫码咨询 ↑↑↑来源 | 01二进制&#xff08;ID:gh_d1999add1857&#xff09;编辑 | Jane【导语】作者自称是一个经常逛 B 站的肥宅。最近 B 站上流行的视频素材除了“换脸”&#xff0c;其次就要属…

javascript 操作Word和Excel的实现代码

1.保存html页面到word 复制代码 代码如下:<HTML> <HEAD> <title> </title> </HEAD> <body> <form id"form"> <table id "PrintA" width"100%" border"1" cellspacing"0" cel…

【C++】C++11新增关键字详解

目录一、auto1、auto 用来声明自动变量&#xff0c;表明变量存储在栈&#xff08;C11之前&#xff09;2、auto用于推断变量类型示例&#xff08;C11&#xff09;3、声明或定义函数时作为函数返回值的占位符&#xff0c;此时需要与关键字 decltype 一起使用。&#xff08;C11&am…

linux批量创建用户和密码

老男孩教育第五关实战考试题&#xff1a;批量创建10个用户stu01-stu10&#xff0c;并且设置随机8位密码&#xff0c;要求不能用shell的循环&#xff08;例如&#xff1a;for,while等&#xff09;&#xff0c;只能用linux命令及管道实现。 方法1&#xff1a;[rootoldboy /]# ech…

“重构”黑洞:26岁MIT研究生的新算法 | 人物志

点击上方↑↑↑蓝字关注我们~「2019 Python开发者日」全日程揭晓&#xff0c;请扫码咨询 ↑↑↑整理 | 若名出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09;这是一个重要时刻。除了发布跟丈夫的两张合照外&#xff0c;Katie Bouman 在 Facebook 上鲜有内容更新&#…

【Ubuntu】VirtualBox显卡驱动VBoxVGA、VBoxSVGA、VMSVGA +3D对播放视频的影响

一、VBOXVGA、VMSVGA、VBOXSVGA简述 VBOXVGA和VBOXSVGA是vbox自己的&#xff0c;SVGA比VGA先进一点&#xff0c; VBoxSVGA: 使用Linux或者 Windows 7或者更高版本的新vm的默认图形控制器。 与传统的VBoxVGA选项相比&#xff0c;此图形控制器可提高性能和3D支持。 VBoxVGA: 将这…

MFC中利用CFileDialog选择文件并读取文件所遇到的问题和解决方法

在用MFC编写一个上位机时&#xff0c;需要实现选择和读取一个二进制文件&#xff0c;本来以为很简单的但是在实现过程中遇到很多问题&#xff0c;所幸都一一解决&#xff0c;这里做一下记录。 首先在实现文件选择&#xff0c;在界面上设置一个按钮&#xff0c;并在点击事件函数…

百度智能云一口气发布 14 个新产品,三大视频解决方案,产品最高降价 50%

产业智能化的浪潮正在加速传统互联网行业的升级&#xff0c;视频行业将成为最大的受益者。4 月 11 日&#xff0c;在 2019ABC INSPIRE 百度云智峰会上&#xff0c;百度副总裁、百度智能云总经理尹世明宣布&#xff0c;“百度云” 品牌全面升级为 “百度智能云”&#xff0c;以 …

开源代码hosting openfoundryfrom tw

http://www.openfoundry.org

倒计时1天!「2019 Python开发者日」报名即将关闭(附参会提醒)

「2019 Python开发者日」倒计时最后1天&#xff0c;仅剩少量余票&#xff0c;请扫码咨询 ↑↑↑相信很多人听过之前的 Python 进入小学课本、Python 进入浙江省高考等新闻&#xff0c;那么&#xff0c;有这么多头衔加持的 Python 究竟魅力在哪&#xff1f;与人工智能、大数据捆…

【Gstreamer】在虚拟机中无法使用硬件加速:gstreamer1.0-vaapi

1、问题描述 在虚拟机中,使用gstreamer播放视频,在没有安装gstreamer1.0-vaapi库时,还是正常的;在安装gstreamer1.0-vaapi后,不能播放视频。 错误信息如下: libva info: VA-API version 0.39.0 libva info: va_getDriverName() returns -1 libva error: va_getDriverNa…

如何在阿里云上安全的存放您的配置 - 续

在《如何在阿里云上安全的存放您的配置》一文中&#xff0c;我们介绍了如何通过ACM存放您的敏感配置&#xff0c;并进行加密。这样做的目的有两个&#xff1a; 在应用程序或对应生产环境容器或系统中&#xff0c;无需持久化任何敏感数据信息(如数据库连接串&#xff0c;等)&…

VLAN-VTP-Trunk

VLAN(Virtual LAN) VLAN可以隔离2层的广播域。A VLAN &#xff1d;&#xff08;一个&#xff09; 广播域 &#xff1d; &#xff08;一个&#xff09;逻辑子网路由器是隔离广播域的单个端口只能承载单个VLAN的流量。使用VLAN好处&#xff1a;1.有效的带宽利用2.提高了安全性3…