当前位置: 首页 > news >正文

C++智能指针(二)——weak_ptr初探

文章目录

  • 1. shared_ptr 存在的问题
  • 2. 使用weak_ptr
    • 2.1 初始化 weak_ptr
    • 2.2 访问数据
  • 3. 附录
  • 4. 参考文献


1. shared_ptr 存在的问题

shared_ptr 的引入要解决普通指针存在的一些问题一样,weak_ptr 的引入,也是因为 shared_ptr 本身在某些情况下,存在一些问题或有一些不完善的地方,考虑以下两个场景:

  • 循环引用(cyclic references)。如果两个对象使用 shared_ptrs 互相引用,那么就算将两个对象指针设为nullptr,此时理应释放资源,但由于内部的循环引用,此时 shared_ptrs 的 use_count() = 1,导致并不会释放资源

    下面为循环引用的一个具体示例代码:
#include <iostream>
#include <string>
#include <vector>
#include <memory>
using namespace std;
class Person {
public:
string name;
shared_ptr<Person> mother;
shared_ptr<Person> father;
vector<shared_ptr<Person>> kids;
Person (const string& n,
shared_ptr<Person> m = nullptr,
shared_ptr<Person> f = nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
cout << "delete " << name << endl;
}
};
shared_ptr<Person> initFamily (const string& name)
{
shared_ptr<Person> mom(new Person(name+"’s mom"));
shared_ptr<Person> dad(new Person(name+"’s dad"));
shared_ptr<Person> kid(new Person(name,mom,dad));
mom->kids.push_back(kid);
dad->kids.push_back(kid);
return kid;
}
int main()
{
shared_ptr<Person> p = initFamily("nico");
cout << "nico’s family exists" << endl;
cout << "- nico is shared " << p.use_count() << " times" << endl;
cout << "- name of 1st kid of nico’s mom: "
<< p->mother->kids[0]->name << endl;
p = initFamily("jim");
cout << "jim’s family exists" << endl;
}

首先,initFamily() 创建了三个Person对象:mon,dad 和 kid。kid 使用了 mom 和 dad 的共享指针进行创建。mom 和 dad 也将 kid 共享指针插入到 vector 中,最后将 kid 指针返回给 p,initFamily() 调用完结果如下图所示。

kid 有指向 mom 和 dad 的指针,mom 和 dad 中也有指向 kid 的指针,此时循环引用就产生了。因此这里 p 的 use_count=3,所以当赋值一个新的Person给p或者让p为nullptr,或者在 main() 末尾离开了 p 的作用域 —— 没有 Person 对象会被释放,因为每个至少有一个指针指向,因此输出 delete name 永远不会调用,实际输出如下:

nico’s family exists
- nico shared 3 times
- name of 1st kid of nicos mom: nico
jim’s family exists
  • 如果只是想共享而不是想拥有对象。即一个指针的生命周期要长于指向对象的生命周期。此时使用 shared_ptrs 会导致无法释放资源,使用普通指针存在访问释放资源的风险,后续对weak_ptr使用的讲解中进一步说明。

2. 使用weak_ptr

鉴于上面 shared_ptr 存在的问题,C++11 提供了 weak_ptr 类,允许共享对象,但并不实际拥有对象,这个类需要传入一个共享指针来创建。当最后一个共享指针失去对象所有权(要释放空间与资源了),共享对象的 weak_ptr 自动设为空(本来就没有对象的所有权,自然也不负责对于空间与资源的释放) 。

我们使用 weak_ptr 改写上面的代码:

class Person {
public:
string name;
shared_ptr<Person> mother;
shared_ptr<Person> father;
vector<weak_ptr<Person>> kids; // weak pointer !!!
Person (const string& n,
shared_ptr<Person> m = nullptr,
shared_ptr<Person> f = nullptr)
: name(n), mother(m), father(f) {
}
~Person() {
cout << "delete " << name << endl;
}
};

通过使用 weak_ptr 打破共享指针的循环引用,只有 kid 指向父母的指针使用共享指针,父母指向 kid 的指针使用(下图中的虚线)

这样 p 的 use_coun=1,所以 p 删除时,会释放对应的内存和资源。程序输出如下:

nico’s family exists
- nico shared 1 times
- name of 1st kid of nicos mom: nico
delete nico
delete nico’s dad
delete nico’s mom
jim’s family exists
delete jim
delete jim’s dad
delete jim’s mom

下面详细讲解 weak_ptr 的使用

2.1 初始化 weak_ptr

因为 weak_ptr 只能使用 shared_ptr 初始化,所以 weak_ptr 只提供了默认构造函数、拷贝构造函数以及传入 shared_ptr 的构造函数,因为不是显式构造函数,所以可以在 vector 中直接插入共享指针(隐式转换):

mom->kids.push_back(kid);
dad->kids.push_back(kid);

2.2 访问数据

之前使用 shared_ptr 访问 vector 中共享指针指向的数据使用以下语法:

p->mother->kids[0]->name

而对于 weak_ptr 则要使用如下语法:

p->mother->kids[0].lock()->name

lock() 获取共享指针,。如果在 lock 获取共享指针时,资源已经被释放了,则返回空的 shared_ptr

此时,再调用操作符 *-> 都会产生未定义行为。

因此,最好在获取共享指针前,首先对资源是否释放进行检查,有如下 3 种方法:

  1. 调用 expired() 方法,如果 weak_ptr 不再共享一个对象则返回 true。这与检查 use_count() 是否等于 0 是等价的,但可能运行速度更快
  2. 可以显式将 weak_ptr 使用对应构造函数转换为 shared_ptr。如果此时没有合法的引用对象,则这个构造函数抛出一个 bad_weak_ptr 异常。 这是一个派生自 std::exception 的一个异常,what() 返回 bad_weak_ptr (每个设备上实现有所差异)。
  3. 可以调用 use_count() 查询关联对象所有者的数量。如果返回值是 0,这将不会再有合法对象。这个方法最好只是在debug时使用,因为效率不高

三种方法的具体代码如下:

try {
shared_ptr<string> sp(new string("hi")); // create shared pointer
weak_ptr<string> wp = sp; // create weak pointer out of it
sp.reset(); // release object of shared pointer
cout << wp.use_count() << endl; // prints: 0
cout << boolalpha << wp.expired() << endl; // prints: true
shared_ptr<string> p(wp); // throws std::bad_weak_ptr
}
catch (const std::exception& e) {
cerr << "exception: " << e.what() << endl; // prints: bad_weak_ptr
}

3. 附录

A. weak_ptr 操作列表


4. 参考文献

《The C++ Standard Library》A Tutorial and Reference, Second Edition, Nicolai M. Josuttis.

相关文章:

C++智能指针(二)——weak_ptr初探

文章目录 1. shared_ptr 存在的问题2. 使用weak_ptr2.1 初始化 weak_ptr2.2 访问数据 3. 附录4. 参考文献 1. shared_ptr 存在的问题 与 shared_ptr 的引入要解决普通指针存在的一些问题一样&#xff0c;weak_ptr 的引入&#xff0c;也是因为 shared_ptr 本身在某些情况下&…...

540 - Team Queue (UVA)

题目链接如下&#xff1a; Online Judge 对比刘汝佳的代码&#xff0c;我没有用queue来排整个队伍&#xff0c;因为那样的话遍历整个队伍太麻烦&#xff0c;vector比较方便。但vector删除元素比较耗时&#xff0c;所以就不删了&#xff0c;仅仅用pivot来指代目前队伍的开始。…...

投资组合之如何估值

文章目录 如何估值一、PE估值法1、PE估值法的定义2、参考标准&#xff08;1&#xff09;常规标准&#xff1a;25倍合理市盈率。&#xff08;2&#xff09;同行业对比。&#xff08;3&#xff09;跟历史市盈率相比。 3、PE估值法的适用范围4、PE估值法的优势5、PE估值法的劣势&a…...

2024届通信工程保研经验分享(预推免入营即offer)

2024届通信工程保研经验分享&#xff08;预推免入营即offer&#xff09; BackGround夏令营情况&#xff1a;预推免情况&#xff1a; BackGround 本科院校&#xff1a;末九 专业&#xff1a;通信工程 rank&#xff1a;3/123&#xff08;预推免绩点排名&#xff09;&#xff0…...

L2-025 分而治之 - java

L2-025 分而治之 时间限制 600 ms 内存限制 64 MB 题目描述&#xff1a; 分而治之&#xff0c;各个击破是兵家常用的策略之一。在战争中&#xff0c;我们希望首先攻下敌方的部分城市&#xff0c;使其剩余的城市变成孤立无援&#xff0c;然后再分头各个击破。为此参谋部提供了若…...

Python+高光谱数据预处理-机器学习-深度学习-图像分类-参数回归

涵盖高光谱遥感数据处理的基础、python开发基础、机器学习和应用实践。重点解释高光谱数据处理所涉及的基本概念和理论&#xff0c;旨在帮助学员深入理解科学原理。结合Python编程工具&#xff0c;专注于解决高光谱数据读取、数据预处理、高光谱数据机器学习等技术难题&#xf…...

免费 AI 编程助手 Amazon CodeWhisperer 体验

文章作者&#xff1a;文章作者&#xff1a;米菲爸爸 2022 年 6 月 23 亚马逊云科技就已经推出了 Amazon CodeWhisperer&#xff08;预览版&#xff09;。经过不到一年的测试和 AIGC的飓风在 2023 年 4 月 18 日实时 AI 编程助手 Amazon CodeWhisperer正式可用 Amazon CodeWhis…...

【Linux】从零开始学习Linux基本指令(一)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;Linux入门 &#x1f525;该文章主要了解Linux操作系统下的基本指令。 目录&#xff1a; ⌛️指令的理解⏳目录和文件的理解⏳一些常见指令✉…...

Java GC 算法

一、概述 理解Java虚拟机垃圾回收机制的底层原理&#xff0c;是成为一个高级Java开发者的基本功。本文从底层的垃圾回收算法开始&#xff0c;着重去阐释不同垃圾回收器在算法设计和实现时的一些技术细节&#xff0c;去探索「why」这一部分&#xff0c;通过对比不同的垃圾回收算…...

vue3 v-html中使用v-viewer

安装&#xff1a;npm install v-viewernext 在main.js中配置 import “viewerjs/dist/viewer.css”; import Viewer from “v-viewer”; app.use(Viewer, { Options: { inline: true, //默认值&#xff1a;false。启用内联模式。 button: true, //在查看器的右上角显示按钮。 …...

Leetcode算法解析——查找总价格为目标值的两个商品

1. 题目链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 2. 题目描述&#xff1a; 商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况&#xff0c;返回任一结果即可。 示例 1&#xff1a; 输入&#xff1a;price …...

unity游戏开发引擎unity3D开发

Unity&#xff08;也被称为Unity3D&#xff09;是一款强大的跨平台游戏引擎&#xff0c;用于开发2D和3D游戏&#xff0c;以及其他交互式应用程序。以下是Unity游戏开发的一般步骤&#xff1a; 安装和设置Unity&#xff1a; 首先&#xff0c;您需要下载并安装Unity。确保选择适…...

iptables

目录 iptables 匹配规则&#xff1a;由上到下依次匹配&#xff0c;一旦匹配不再匹配 参数 知识点 REJECT与DROP REJECT与DROP的区别 当使用的时REJECT时&#xff0c;客户端访问迅速返回的值是拒绝连接 当使用的是DROP时&#xff0c;返回的时连接超时 REJECT与drop适用…...

竞赛 深度学习LSTM新冠数据预测

文章目录 0 前言1 课题简介2 预测算法2.1 Logistic回归模型2.2 基于动力学SEIR模型改进的SEITR模型2.3 LSTM神经网络模型 3 预测效果3.1 Logistic回归模型3.2 SEITR模型3.3 LSTM神经网络模型 4 结论5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 …...

Spark入门

目录 Spark入门: 概述历史概述SparkCore&#xff1a;RDDSparkSQL:SparkStreamingSpark内核调优 Spark概述 回顾&#xff1a; Hadoop HDFS存储 MR分析计算 YARN调度 Hadoop的MR计算中的shuffle需要落盘&#xff0c;速度不够快。 Spark是一种基于内存的分析计算引擎。 历史…...

react–antd 实现TreeSelect树形选择组件,实现点开一层调一次接口

效果图: 注意: 当选择“否”&#xff0c;开始调接口&#xff0c;不要把点击调接口写在TreeSelect组件上&#xff0c;这样会导致问题出现&#xff0c;没有层级了 部分代码:...

android 固定进度环形刷新效果

android 固定进度无限旋转的环形效果 效果图 效果视频&#xff1a; Record_2023-10-13-17-17-19[1] Activity 中使用 val rotation: ObjectAnimator ObjectAnimator.ofFloat(progressBar, "rotation", 0f, 360f) rotation.duration 000 // 旋转持续时间为2秒 rot…...

python jieba 词性标注 中文词性分类 nlp jieba.posseg

参考&#xff1a;https://blog.csdn.net/yellow_python/article/details/83991967 from jieba.posseg import dt dt.word_tag_tab[好看] >>> vflag_en2cn { ‘a’: ‘形容词’, ‘ad’: ‘副形词’, ‘ag’: ‘形语素’, ‘an’: ‘名形词’, ‘b’: ‘区别词’, ‘…...

LeetCode 每日一题 2023/10/9-2023/10/15

记录了初步解题思路 以及本地实现代码&#xff1b;并不一定为最优 也希望大家能一起探讨 一起进步 目录 10/9 2578. 最小和分割10/10 2731. 移动机器人10/11 2512. 奖励最顶尖的 K 名学生10/12 2562. 找出数组的串联值10/13 1488. 避免洪水泛滥10/14 136. 只出现一次的数字10/1…...

相似性搜索:第 3 部分--混合倒排文件索引和产品量化

接续前文&#xff1a;相似性搜索&#xff1a;第 2 部分&#xff1a;产品量化 SImilarity 搜索是一个问题&#xff0c;给定一个查询的目标是在所有数据库文档中找到与其最相似的文档。 一、介绍 在数据科学中&#xff0c;相似性搜索经常出现在NLP领域&#xff0c;搜索引擎或推…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Java - Mysql数据类型对应

Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...

MySQL用户和授权

开放MySQL白名单 可以通过iptables-save命令确认对应客户端ip是否可以访问MySQL服务&#xff1a; test: # iptables-save | grep 3306 -A mp_srv_whitelist -s 172.16.14.102/32 -p tcp -m tcp --dport 3306 -j ACCEPT -A mp_srv_whitelist -s 172.16.4.16/32 -p tcp -m tcp -…...

基于IDIG-GAN的小样本电机轴承故障诊断

目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) ​梯度归一化(Gradient Normalization)​​ (2) ​判别器梯度间隙正则化(Discriminator Gradient Gap Regularization)​​ (3) ​自注意力机制(Self-Attention)​​ 3. 完整损失函数 二…...

计算机基础知识解析:从应用到架构的全面拆解

目录 前言 1、 计算机的应用领域&#xff1a;无处不在的数字助手 2、 计算机的进化史&#xff1a;从算盘到量子计算 3、计算机的分类&#xff1a;不止 “台式机和笔记本” 4、计算机的组件&#xff1a;硬件与软件的协同 4.1 硬件&#xff1a;五大核心部件 4.2 软件&#…...

PostgreSQL——环境搭建

一、Linux # 安装 PostgreSQL 15 仓库 sudo dnf install -y https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm# 安装之前先确认是否已经存在PostgreSQL rpm -qa | grep postgres# 如果存在&#xff0…...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

DBLP数据库是什么?

DBLP&#xff08;Digital Bibliography & Library Project&#xff09;Computer Science Bibliography是全球著名的计算机科学出版物的开放书目数据库。DBLP所收录的期刊和会议论文质量较高&#xff0c;数据库文献更新速度很快&#xff0c;很好地反映了国际计算机科学学术研…...

【安全篇】金刚不坏之身:整合 Spring Security + JWT 实现无状态认证与授权

摘要 本文是《Spring Boot 实战派》系列的第四篇。我们将直面所有 Web 应用都无法回避的核心问题&#xff1a;安全。文章将详细阐述认证&#xff08;Authentication) 与授权&#xff08;Authorization的核心概念&#xff0c;对比传统 Session-Cookie 与现代 JWT&#xff08;JS…...