《白话C++》第10章 STL和boost,Page85 std::shared_ptr常用功能

std::shared_ptr基本用法包括:

(1)取裸指针

//get()成员取回裸指针
std::shared_ptr <int> pa(new int(5));
int* p = pa.get(); /**< 取回裸指针 */

(2)判断是否为空

肯定可以这样写:

std::shared_ptr <int> pa;
if(pa.get() != nullptr)
...

或者更具C++风格的判断指针是否为空:

if(!pa.get())
...

以上都是通过get()取得裸指针,不过shared_ptr(其他智能指针也一样)重载了‘!’ 操作符。

对一个智能指针执行逻辑取反(‘!’)操作,当它所管理的裸指针为空时,返回真:

std::shared_ptr <int> pa;
if(!pa)
    ...

也可以直接拿来和nullptr作相等比较,因为shared_ptr(其他智能指针也一样)重载了和指针的逻辑相等判断(‘==’)操作:

if(pa == nullptr)
    ...

再试试逻辑不等判断操作‘!=’。默认空构造产生的shared_ptr拥有空的裸指针,即拥有一个nullptr。

std::shared_ptr <int> pb;
if(pb == nullptr)  //和nullptr做相等比较
{
    cout << "pb的裸指针是空指针" << endl;
}

(3)比较操作

两个shared_ptr也可以用来比较,并且编译器能够帮我们杜绝风马牛不相及的比较

cout << "----------test5----------" << endl;
/**< 比较操作 */
std::shared_ptr <int> pi(new int);
std::shared_ptr <int> pi2(pi);

//断定pi和pi2相等(所拥有的指针指向相同)
assert(pi2 == pi); //成立

std::shared_ptr <char> pc(new char);
    if(pi == pc) //编译出错

比较pc和pi时,编译就不通过。一个指向int数据的指针,一个指向char数组的指针,二者有什么好比的呢?

为了模拟裸指针间的比较,shared_ptr也提供‘<’、‘>’、‘<=’及‘>=’等大小的比较,以及前面提到的‘==’和‘!=’。

(4)拷贝构造、赋值

std::shared_ptr <int> pa(new int);
std::shared_ptr <int> pb(pa); ///拷贝构造
std::shared_ptr <int> pc(new int);
pc = pb; ///赋值

002行,pb从pa复制并构造时,主要结果一是二者所拥有的裸指针指向同一对象内存 ;二是二者所共有“引用计数”是2。

003行,创建了pc,它拥有自己的裸指针(后成‘原裸指’)。此时它和pa、pb没有关系。

004行,pc改为从pb赋值,它将丢弃‘原裸指’,改为和pa、pb同指向。赋值时,‘原裸指’将被释放(因为没有别的shared_ptr拥有)。

严重危险的情况发生在下面这样的代码中:

int * pi = new int;
/**< 管理着共同的裸指针,而不是共同管理同一个裸指针 */
std::shared_ptr <int> sia(pi); //这没错
std::shared_ptr <int> sib(pi); //这?

sia的构造没有问题,构造之后的智能指针对象sia就托管了裸指针pi所指向的内存(因此后面不应该有delete pi的操作)。

关键是sib的构建,它的构造入参也是裸指针pi,而不是同类sia。这就造成了sia认为:我是第一个管理pi的shared_ptr;然而sib也认为自己是第一个管理pi的shared_ptr。

注意,此时sia和sib的状态是“它们管理着共同的裸指针”,而非我们所要的“它们共同管理同一个裸指针”,此时sia中的引用计数是1,而sib也一样,二者中任何一个结束生命周期,都会去释放pi所指向的内存。

【危险】:同一裸指针,确保从shared_ptr对象开始“分享”

做法很简单:如果你有一个裸指针需要使用shared_ptr管理,就确保一开始只用一个shared_ptr对象在创建时托管该裸指针,然后从第二个shared_ptr开始,就只从之前的shared_ptr拷贝构建。

“不作就不会死”

再看看以下“不作就不会死”的代码:

std::shared_ptr<int> sia(new int);
std::shared_ptr<int> sib(sia.get());

明明已经有一个智能指针sia了,可sib非要从sia身上得到裸指针然后再另立山头管理。

下面的代码犯了类似的问题

struct S2;

struct S1
{
    S1(S2* ptr); ///构造入参是一个S2类型指针

    std::shared_ptr<S2> ps2;///成员数据
};

struct S2
{
    S2();
    ~S2();

    S1 * ps1; ///属性
};

S1::S1(S2 * ptr)
    : ps2(ptr) ///初始化共享指针ps2, ps2管理着指针ptr
{
    cout << "调用了S1构造函数,并将入参委托给shared_ptr ps2" << endl;
}
S2::S2()
{
    cout << "调用了S2构造函数,并以S2自身作为入参构造一个S1" << endl;
    ps1 = new S1(this);
}

S2::~S2()
{
    delete ps1;
}

void bad_test_1()
{
    S2 s2;  ///s2是一个栈对象,
}

void bad_test_2()
{
    cout << " new一个S2,委托给scoped_ptr " << endl;
    boost::scoped_ptr <S2> ps2 (new S2);
}

先看bad_test_1(),该函数创建一个S2的栈对象;于是看23行的S2的构造函数,发现它构造了一个S1的堆对象,并且以自身作为指针入参传递给S1的构造函数;继续跟踪,看S1构造函数,关注它取入参(一个指向某S2对象的指针)作什么事。

请看019行,这个指针被用来作为S1的成员数据ps2的构造入参,而ps2是一个share_ptr<S2>。

第一个问题出现了:ps2是一个智能指针,但它却管理了一个并不需要释放的栈对象,即bad_test_1()函数中s2.

bad_test_2()函数中创建的堆对象,已经托管给scoped_ptr <S2>,后面再七传八传最终又一次委托给某个shared_ptr<S2>。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/395239.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MobaXterm下载安装及SSH远程教程

一、MobaXterm的简介 MobaXterm是一款功能强大的远程计算工具&#xff0c;集成了诸多网络工具和便利功能&#xff0c;包括SSH、X11服务器、SFTP等&#xff0c;支持Windows系统。用户可以使用MobaXterm来轻松管理远程服务器&#xff0c;进行文件传输&#xff0c;远程桌面显示等操…

8、内网安全-横向移动RDPKerberos攻击SPN扫描WinRMWinRS

用途&#xff1a;个人学习笔记&#xff0c;有所借鉴&#xff0c;欢迎指正 目录 一、域横向移动-RDP-明文&NTLM 1.探针服务&#xff1a; 2.探针连接&#xff1a; 3.连接执行&#xff1a; 二、域横向移动-WinRM&WinRS-明文&NTLM 1.探针可用&#xff1a; 2.连接…

语义相关性评估指标:召回率、准确率、Roc曲线、AUC;Spearman相关系数、NDCG、mAP。代码及计算示例。

常规的语义相关性评价可以从检索、排序两个方面进行。这里只贴代码。详细可见知乎https://zhuanlan.zhihu.com/p/682853171 检索 精确率 def pre(true_labels[],pre_labels[]):""":param true_labels: 正样本索引:param pre_labels: 召回样本索引:return: 精…

180144-70-1,6-罗丹明6G-NHS 活化酯,具有高荧光性质的罗丹明家族染料

216699-37-5&#xff0c;793646-39-6&#xff0c;180144-70-1&#xff0c;6-罗丹明6G-NHS 活化酯&#xff0c;6-Rhodamine 6G NHS ester&#xff0c;R6G SE,6-isomer&#xff0c;具有高荧光性质的罗丹明家族染料 您好&#xff0c;欢迎来到新研之家 文章关键词&#xff1a;216…

【存储基础学习笔记】

目录 第一章&#xff1a;存储基础知识第二章&#xff1a;存储的基本概念2.1存储是什么&#xff1f;2.2存储的应用场景2.3存储的硬件结构2.4存储的软件架构2.5存储设备的性能参数和计算方法 第三章&#xff1a;存储阵列关键技术3.1硬盘介绍3.2RAID技术3.3RAID2.0技术 第四章&…

Postgresql 怎么实现在局域网中访问

安装PostgreSQL后&#xff0c;默认情况下只能在本机进行连接访问&#xff0c;如果需要在其他主机上访问PostgreSQL数据库服务器&#xff0c;需要进行配置。 安装连接PostgresSQL数据库可以参考博文&#xff1a;安装连接PostgresSQL数据库教程 一. 整体步骤 主要包括下面几个步…

mmap映射文件使用示例

mmap 零拷贝技术可以应用于很多场景&#xff0c;其中一个典型的应用场景是网络文件传输。 假设我们需要将一个大文件传输到远程服务器上。在传统的方式下&#xff0c;我们可能需要将文件内容读入内存&#xff0c;然后再将数据从内存复制到网络协议栈中&#xff0c;最终发送到远…

Ubuntu系统搭建HadSky论坛并结合内网穿透实现无公网ip远程访问

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

x86下使用硬件实现的任务切换(TSS表)---使用代码讲解

实现任务切换(使用TSS) 视频讲解可以看这一个课程 • The current program, task, or procedure executes a JMP or CALL instruction to a TSS descriptor in the GDT. • The current program, task, or procedure executes a JMP or CALL instruction to a task-gate descri…

冒泡排序及其优化

冒泡排序 int[] arr {1,3,2,9,4,7,2,8};//比较多少轮(n个数字比较n-1次)for(int i0,n arr.length;i<n-1;i) {//每轮比较多少次(n-1-i次)for(int j 0;j<n-1-i;j) {//两两比较if(arr[j] > arr[j1]) { //比较结果为升序排列&#xff0c;如果想要降序排列结果将 >…

计算机网络——18无连接传输UDP

无连接传输UDP UDP “尽力而为的”服务&#xff0c;报文段可能 丢失送到应用进程的报文段乱序 无连接 UDP发送端和接收端之间没有握手每个UDP报文段都被独立的处理 UDP被用于 流媒体DNSSNMP 在UDP上实现可靠传输 在应用层增加可靠性应用特定的差错格式 UDP&#xff1a;用户…

小工具 - 浮点计算器

文章目录 小工具 - 浮点计算器概述笔记FloatCalcDlg.cppFloatCalcDlg.hrcEND 小工具 - 浮点计算器 概述 在学习CE, 在调试过程中, 经常要看内存中浮点对应的4字节内存到底对应的是啥具体的浮点值. e.g. 0x42860000 > 67.00 转换逻辑挺简单的 float CFloatCalcDlg::uint32…

克服数字化三重担忧,从构建身份基础设施开始

随着数字化转型和云迁移的逐步推进&#xff0c;IT 架构逐渐复杂化&#xff0c;基础设施和运营&#xff08;I&O&#xff09;领域已出现了许多创新和新兴技术&#xff0c;例如云计算、边缘计算、云原生、容器技术和智能运维&#xff08;AIOps&#xff09;。这些创新和新技术不…

TCP流量控制+拥塞控制

流量控制&#xff1a; 目标&#xff1a;流量控制主要解决的是发送方和接收方之间处理能力的不匹配问题。它的目的是确保发送方不会发送数据过快&#xff0c;以至于接收方无法及时接收并处理这些数据&#xff0c;从而避免数据包在网络中堆积和丢失。实现方式&#xff1a;在TCP协…

挑战杯 基于GRU的 电影评论情感分析 - python 深度学习 情感分类

文章目录 1 前言1.1 项目介绍 2 情感分类介绍3 数据集4 实现4.1 数据预处理4.2 构建网络4.3 训练模型4.4 模型评估4.5 模型预测 5 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于GRU的 电影评论情感分析 该项目较为新颖&#xff0c;适合作为竞…

Vue3快速上手(八) toRefs和toRef的用法

顾名思义&#xff0c;toRef 就是将其转换为ref的一种实现。详细请看&#xff1a; 一、toRef 1.1 示例 <script langts setup name"toRefsAndtoRef"> // 引入reactive,toRef import { reactive, toRef } from vue // reactive包裹的数据即为响应式对象 let p…

UE蓝图 Cast节点和源码

系列文章目录 UE蓝图 Cast节点和源码 文章目录 系列文章目录Cast节点功能一、Cast节点用法二、Cast节点使用场景三、Cast节点实现步骤四、Cast节点源码 Cast节点功能 在Unreal Engine&#xff08;UE&#xff09;中&#xff0c;Cast节点是一种蓝图系统中的节点&#xff0c;用于…

如何高效利用FMEA,FMEA实施流程有哪些——SunFMEA软件系统

FMEA作为是一种预防性的质量工具&#xff0c;用于识别、评估和解决潜在的设计和过程故障模式。通过FMEA的实施&#xff0c;可以在产品或过程的开发阶段发现并解决潜在问题&#xff0c;从而减少产品或过程的故障风险。如何高效利用FMEA呢&#xff0c;接下来SunFMEA软件和大家一起…

kali虚拟机桥接模式快速设置

第一步&#xff1a;配置 IP、掩码、网关 vim /etc/network/interfaces第二步&#xff1a;配置 DNS&#xff1a; vi /etc/resolv.conf第三步&#xff1a;重启网卡 service networking restart如果还不行建议重启一下虚拟机

CCF-A类MobiCom历年高引论文集免费放送!

MobiCom 高引论文集 MobiCom(International Conference On Mobile Computing And Networking )会议是无线网络和移动计算领域的重要盛会&#xff0c;对推动该领域发展起着积极的推动作用&#xff01;贴心的会议之眼已经免费为大家带来30篇高质量的MobiCom被广泛引用论文&#x…
最新文章