Boost开发指南-3.6weak_ptr
weak_ptr
weak_ptr是为配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator*和->。它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使用情况。
类摘要
template<class T>
class weak_ptr
{
public:weak_ptr(); //构造函数template<class Y> weak_ptr(shared_ptr<Y> const & r);weak_ptr(weak_ptr const & r);~weak_ptr(); //析构函数weak_ptr &operator = (weak_ptr const & r); //赋值long use_count() const; //引用计数bool expired() const; //是否失效指针shared_ptr<T> lock() const; //获取shared_ptrvoid reset(); //重置指针void swap(weak_ptr<T> & b); //交换指针
};
weak_ptr的接口很小,正如它的名字,是一个“弱”指针,但它能够完成一些特殊的工作,足以证明它的存在价值。
用法
weak_ptr被设计为与shared_ptr协同工作,可以从一个shared_ptr或者另一个weak_ptr对象构造,获得资源的观测权。但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。同样,weak_ptr析构时也不会导致引用计数减少,它只是一个静静的观察者。
使用weak_ptr的成员函数 use_count()可以观测资源的引用计数,另一个成员函数expired()的功能等价于use_count()==0,但更快,表示被观测的资源(也就是被shared_ptr管理的资源)已经不复存在。
weak_ptr没有重载operator*和->,这是特意的,因为它不共享指针,不能操作资源,这正是它“弱”的原因。但它可以使用一个非常重要的成员函数lock()从被观测的shared_ptr获得一个可用的shared_ptr对象,把弱关系转换为强关系,从而操作资源。但当expired()==true的时候,lock()函数将返回一个存储空指针的shared_ptr。
shared_ptr<int> sp(new int(10)); //一个shared_ptr
assert(sp.use_count() == 1);weak_ptr<int> wp(sp); //从shared_ptr创建weak_ptr
assert(wp.use_count() == 1); //weak_ptr不影响引用计数if (!wp.expired()) //判断weak_ptr观察的对象是否失效
{shared_ptr<int> sp2 = wp.lock(); //获得一个shared_ptr*sp2 = 100;assert(wp.use_count() == 2); //退出作用域,sp2自动析构,引用计数减1
}assert(wp.use_count() == 1);
sp.reset(); //shared_ptr失效
assert(wp.expired());
assert(!wp.lock()); //weak_ptr将获得一个空指针
enable_shared_from_this
weak_ptr的一个重要用途是获得this 指针的 shared_ptr,使对象自己能够生产shared_ptr管理自己:对象使用weak_ptr观测this指针,这并不影响引用计数,在需要的时候就调用lock()函数,返回一个符合要求的shared_ptr供外界使用。
这个解决方案被实现为一个惯用法,在头文件<boost/enable_shared_from_this.hpp>定义了一个助手类enable_shared_from_this<T>,它的声明摘要如下:
template<class T>
class enable_shared_from_this //辅助类,需要继承使用
public:shared_ptr<T> shared_from_this(); //工厂函数,产生this的shared_ptr
使用的时候只需要让想被shared_ptr管理的类从它派生即可,成员函数shared_from_this()会返回this的shared_ptr。例如:
class self_shared: //一个需要用shared_ptr自我管理的类public enable_shared_from_this<self_shared>
{
public:self_shared(int n) : x(n){}int x;void print(){ cout<< "self_shared : " << x << endl; }
};int main()
{auto sp = make_shared<self_shared>(313);sp->print();auto p = sp->shared_from_this();p->x = 1000;p->print();
}
需要注意的是千万不能对一个普通对象(非shared_ptr管理的对象)使用shared_from_this()获取shared_ptr,例如:
self_shared ss;
auto p = ss.shared_from_this(); //错误
这样虽然语法上正确,编译也无问题,但在运行时会导致shared ptr析构时企图删除一个栈上分配的对象,发生未定义行为。
enable_shared_from_raw
smart_ptr库在未文档化的头文件<boost/smart_ptr/enable_shared_from_raw .hpp>里提供另外一个与 enable_shared_from_this类似的辅助类enable_shared_from_raw,它不要求对象必须被一个shared_ptr管理,可以直接从一个原始指针创建出shared_ptr。
enable_shared_from_raw的类摘要如下:
class enable_shared_from_raw
{
protected:enable_shared_from_raw();enable_shared_from_raw(enable_shared_from_raw const &);enable_shared_from_raw & operator=(enable_shared_from_raw const &);~enable_shared_from_raw()
private :template<class Y> friend class shared_ptr;template<typenameT>friend boost::shared_ptr<T> shared_from_raw(T *);template<typename T>friend boost::weak_ptr<T> weak_from_raw(T *);
};
enable_shared_from_raw利用了shared_ptr的别名构造函数特性,内部持有一个void*的空指针shared_ptr作为引用计数的观察者,从而达到管理原始指针的目的。
enable_shared_from_raw同样需要继承使用,但它不是模板类,所以不需要指定模板参数,比 enable_shared_from_this写法上要简单一些。它不提供成员函数shared_from_this(),而是用两个friend函数shared_from_raw()和weak_from_raw()完成创建智能指针的工作。
但请注意:在调用shared_from_raw()后,由于存在shared_ptr成员变量的原因,对象内部会有一个shared_ptr的强引用,所以即使其他的 shared_ptr都析构了原始指针也不会被自动删除(因为use_count() >=1)——这使得enable_shared_from_raw用法略微不同于enable_shared_from_this,它可以安全地从一个普通对象而非指针创建出shared_ptr。
示范enable_shared_from_raw用法的代码如下:
#include <boost/smart_ptr/enable_shared_from_raw.hpp>class raw_shared :public boost::enable_shared_from_raw
{
public:raw_shared(){std::cout << "raw_shared ctor" << std::endl;}~raw_shared(){std::cout << "raw_shared dtor" << std::endl;}
};int main()
{raw_shared x; //一个普通对象assert(weak_from_raw(&x).use_count() == 1); //此时无引用,注意要用&取地址auto px = shared_from_raw(&x); //获取shared_ptrassert(px.use_count() == 2); //引用计数为2!
} //对象自动删除
把enable_shared_from_raw应用于原始指针要当心,使用不当有可能造成内存泄漏:
int main()
{auto p = new raw_shared; //创建一个原始指针auto wp = weak_from_raw(p); //获取weak_ptrassert(wp.use_count() == ); //此时无引用auto sp = shared_from_raw(p); //获取shared_ptrassert(sp.use_count() == 2); //引用计数为2!auto sp2 = sp; //拷贝一个shared_ptrauto wp2 = weak_from_raw(p); //获取weak_ptrassert(wp2.use_count() == 3); //引用计数为3
} //对象没有被删除,内存泄露!
如果在代码里的某个时刻使用shared_ptr来管理原始指针——而不是调用shared_from_raw(),那么指针的管理权就会转移到 shared_ptr,从而可以正确地自动销毁,例如:
int main()
{auto p = new raw_shared; //创建一个原始指针decltype(shared_from_raw(p)) spx(p); //使用shared_ptr管理指针... //其他操作
} //对象被自动删除
enable_shared_from_raw的用法比较特殊,实际应用的场景较少,也许这就是它没有在 Boost库里被文档化的原因。
打破循环引用
有的时候代码中可能会出现“循环引用”,这时shared_ptr的引用计数机制就会失效,导致不能正确释放资源,例如:
#include <boost/smart_ptr.hpp>
using namespace boost;class node //一个用于链表节点的类
{
public:~node() //析构函数输出信息{std::cout << "deleted" << std::endl;}typedef shared_ptr<node> ptr_type; //指针类型使用shared_ptrptr_type next; //后继指针
};int main()
{auto p1 = make_shared<node>(); //两个节点对象auto p2 = make_shared<node>();p1->next = p2; //形成循环链表p2->next = p1; assert(p1.use_count() == 2); //每个shared_ptr的引用计数都是2assert(p2.use_count() == 2);} //退出作用域,shared_ptr无法正确析构
上面的代码中两个节点对象互相持有对方的引用,每一个shared_ptr的引用计数都是2,因此在析构时引用计数没有减至0,不会调用删除操作,导致内存泄漏。
这个时候我们就可以使用weak_ptr,因为它不会增加智能指针的引用计数,这样就把原来的强引用改变为弱引用,在可能存在循环引用的地方打破了循环,而在真正需要shared_ptr的时候调用weak_ptr的lock()函数:
class node //一个用于链表节点的类
{
public:~node() //析构函数输出信息{std::cout << "deleted" << std::endl;}typedef weak_ptr<node> ptr_type; //指针类型使用weak_ptrptr_type next; //后继指针
};int main()
{auto p1 = make_shared<node>(); //两个节点对象auto p2 = make_shared<node>();p1->next = p2; //形成循环链表p2->next = p1; //引用使用了weak_ptr所以正常assert(p1.use_count() == 1); //每个shared_ptr的引用计数都是2assert(p2.use_count() == 1); //没有了循环引用if (!p1->next.expired()) //检查弱引用是否有效{auto p3 = p1->next.lock(); //调用lock()获得强引用}} //退出作用域,shared_ptr均正确析构
代码示例
#include <iostream>
//using namespace std;#include <boost/smart_ptr.hpp>
using namespace boost;//void case1()
{shared_ptr<int> sp(new int(10));assert(sp.use_count() == 1);weak_ptr<int> wp(sp);assert(wp.use_count() == 1);assert(!wp.empty());if (!wp.expired()){shared_ptr<int> sp2 = wp.lock();*sp2 = 100;assert(wp.use_count() == 2);}assert(wp.use_count() == 1);sp.reset();assert(wp.expired());assert(!wp.lock());
}//class self_shared :public enable_shared_from_this<self_shared>
{
public:self_shared(int n) :x(n) {}int x;void print(){std::cout << "self_shared:" << x << std::endl;}
};void case2()
{auto sp = make_shared<self_shared>(313);sp->print();auto p = sp->shared_from_this();p->x = 1000;p->print();
}//class node
{
public:~node(){std::cout << "deleted" << std::endl;}typedef weak_ptr<node> ptr_type;//typedef shared_ptr<node> ptr_type;ptr_type next;
};void case3()
{auto p1 = make_shared<node>();auto p2 = make_shared<node>();p1->next = p2;p2->next = p1;assert(p1.use_count() == 1);assert(p2.use_count() == 1);if (!p1->next.expired()){auto p3 = p1->next.lock();}
}//
#include <boost/smart_ptr/enable_shared_from_raw.hpp>class raw_shared :public enable_shared_from_raw
{
public:raw_shared(){std::cout << "raw_shared ctor" << std::endl;}~raw_shared(){std::cout << "raw_shared dtor" << std::endl;}
};void case4()
{raw_shared x;assert(weak_from_raw(&x).use_count() == 1);auto px = shared_from_raw(&x);assert(px.use_count() == 2);auto p = new raw_shared;auto wp = weak_from_raw(p);assert(wp.use_count() == 1);decltype(shared_from_raw(p)) spx(p);auto sp = shared_from_raw(p);//std::cout << sp.use_count() << std::endl;assert(sp.use_count() == 2);//decltype(sp) spx(p);auto sp2 = sp;auto wp2 = weak_from_raw(p);assert(wp2.use_count() == 3);
}//int main()
{case1();case2();case3();case4();
}

相关文章:
Boost开发指南-3.6weak_ptr
weak_ptr weak_ptr是为配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,没有重载 operator*和->。它的最大作用在于协助shared_ptr工作,像旁观者那样观测资源的使…...
Swift 周报 第三十三期
文章目录 前言新闻和社区App 内购买项目和订阅即将实行价格与税率调整为家庭提供安全的 App 体验 提案正在审查的提案 Swift论坛推荐博文话题讨论关于我们 前言 本期是 Swift 编辑组自主整理周报的第二十四期,每个模块已初步成型。各位读者如果有好的提议ÿ…...
网络空间安全及计算机领域常见英语单词及短语——网络安全(一)
目录 网络空间安全常见英语单词没事儿读着玩儿相关知识扫盲 CSDN的小伙伴们,我快回来咯!网络空间安全常见英语单词 Cybersecurity 网络安全Network security 网络安全Information security 信息安全Data protection 数据保护Threat analysis 威胁分析Ri…...
Go基准测试Benchmark
Go语言自带了一个强大的测试框架,其中包括基准测试(Benchmark)功能,基准测试用于测量和评估一段代码的性能。 我们可以通过在Go的测试文件中编写特殊格式的函数来创建基准测试。测试文件的命名遵守原函数名称_test.go 的格式。 基…...
docker容器的基本操作
一、查看Docker的版本信息 [roothuyang1 ~]# docker version 二、查看docker的详细信息 [roothuyang1 ~]# docker info 三、Docker镜像操作 Docker创建容器前需要本地存在对应的镜像,如果本地加载不到相关镜像,Docker默认就会尝试从镜像仓库https://hu…...
MySQL绿色安装和配置
1、 从地址http://dev.mysql.com/downloads/mysql/中选择windows的版本下载。 2、 mysql各个版本的简介 (1) MySQL Community Server 社区版本,开源免费,但不提供官方技术支持。 (2) MySQL Enterprise Ed…...
《cuda c编程权威指南》03 - cuda小功能汇总
1. 计时 1.1 linux #include <sys/time.h>double cpuSecond() {struct timeval tp;gettimeofday(&tp, NULL);return ((double)tp.tv_sec (double)tp.tv_usec*1e-6); }// 调用 double start cpuSecond(); kernel_name << <grid, block >> > (ar…...
Java:Java程序通过执行系统命令调用Python脚本
本文实现功能:Java程序调用Python脚本 Python脚本 import sysdef add(x, y):return x yif __name__ "__main__":print(add(int(sys.argv[1]), int(sys.argv[2])))直接执行 $ python math.py 1 2 3Java程序调用Python脚本 package io.github.mouday.…...
this is incompatible with sql_mode=only_full_group_by
查看配置 select global.sql_mode 在sql命令行中输入select sql_mode 能够看到sql_mode配置,如果有ONLY_FULL_GROUP_BY,则需要修改 在mysql5.7.5后,ONLY_FULL_GROUP_BY是默认选项,所以就会导致group by的问题 set sql_mode‘复制去掉ONLY_F…...
GCC编译选项
当使用GCC编译器时,可以根据不同的需求选择适当的编译选项来控制编译过程和生成的代码的行为。以下是一些常见的GCC编译选项的归纳: 优化选项: -O0: 不进行优化,保留原始的C代码结构。-O1: 启用基本优化级别,进行简单…...
信息安全战线左移!智能网联汽车安全亟需“治未病”
当汽车由典型的工业机械产品逐步发展成为全新的智能移动终端,汽车的安全边界发生了根本性改变,信息安全风险和挑战不断增加。 面对复杂的异构网络、异构系统及车规级特异性要求,智能智能网联汽车信息安全到底要如何防护,已经成为…...
服务器介绍
本文章转载与b战up主谈三国圈,仅用于学习讨论,如有侵权,请联系博主 机架型服务器 堆出同时服务百万人次机组 刀型服务器 服务器炸了 比如用户访问量暴增 超过机组的峰值处理能力,进而导致卡顿或炸服, 适合企业的塔式…...
Java_25_方法引用
方法引用 方法引用: 方法引用是为了进一步简化Lambda表达式的写法。 方法引用的格式:类型或者对象::引用的方法。 关键语法是:“::” 小结:方法引用可以进一步简化Lambda表达式的写法。关键语法是:“::”范例代码&…...
QT基于TCP协议实现数据传输以及波形绘制——安卓APP及Windows程序双版本
文章代码有非常非常之详细的解析!!!诸位可放心食用 这个玩意我做了两个,一个是安卓app,一个是Windows程序。代码并非全部都是由我从无到有实现,只是实现了我想要的功能。多亏了巨人的肩膀,开源…...
mac 中 brctl 怎么用
mac 中 brctl 怎么用 mac 中 brctl 怎么用1.使用 Homebrew 安装 bridge2.安装完成后,你可以使用 bridge 命令来管理网络桥接。 mac 中 brctl 怎么用 在 macOS 中,没有官方提供的 brctl 命令行工具。但是,你可以使用一个名为 bridge 的开源工…...
20.2 HTML 常用标签
1. head头部标签 <head>标签用于定义网页的头部, 其中的内容是给浏览器读取和解析的, 并不在网页中直接显示给用户. <head>标签通常包含以下一些常见的子标签: - <title>: 定义网页的标题, 在浏览器的标题栏或标签页上显示. - <meta>: 用于设置网页的…...
mysql_2.5——【约束】详解
1、查看约束 SHOW CREATE TABLE table_name 2、主键约束(PRIMARY KEY) 主键约束最显著的特征是主键列中的值是不允许重复(唯一)的,通过主键约束可强制表 的实体完整性。当创建或更改表时可通过定义 primary key 约束来创建主键。一个表只 能有一个primary key约束…...
回归预测 | MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络多输入单输出回归预测
回归预测 | MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络多输入单输出回归预测 目录 回归预测 | MATLAB实现POA-CNN-BiLSTM鹈鹕算法优化卷积双向长短期记忆神经网络多输入单输出回归预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 MATLA…...
opencv顺时针,逆时针旋转视频并保存视频
原视频 代码 import cv2# 打开视频文件 video cv2.VideoCapture(inference/video/lianzhang.mp4)# 获取原视频的宽度和高度 width int(video.get(cv2.CAP_PROP_FRAME_WIDTH)) height int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))# 创建视频编写器并设置输出视频参数 fourcc …...
【LeetCode】最小路径和
最小路径和 题目描述算法流程编程代码 链接: 最小路径和 题目描述 算法流程 编程代码 class Solution { public:int minPathSum(vector<vector<int>>& grid) {int m grid.size();int n grid[0].size();vector<vector<int>> dp(m1,vector<in…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
Unity3D中Gfx.WaitForPresent优化方案
前言 在Unity中,Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染(即CPU被阻塞),这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案: 对惹,这里有一个游戏开发交流小组&…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
「全栈技术解析」推客小程序系统开发:从架构设计到裂变增长的完整解决方案
在移动互联网营销竞争白热化的当下,推客小程序系统凭借其裂变传播、精准营销等特性,成为企业抢占市场的利器。本文将深度解析推客小程序系统开发的核心技术与实现路径,助力开发者打造具有市场竞争力的营销工具。 一、系统核心功能架构&…...
Modbus RTU与Modbus TCP详解指南
目录 1. Modbus协议基础 1.1 什么是Modbus? 1.2 Modbus协议历史 1.3 Modbus协议族 1.4 Modbus通信模型 🎭 主从架构 🔄 请求响应模式 2. Modbus RTU详解 2.1 RTU是什么? 2.2 RTU物理层 🔌 连接方式 ⚡ 通信参数 2.3 RTU数据帧格式 📦 帧结构详解 🔍…...
6个月Python学习计划 Day 16 - 面向对象编程(OOP)基础
第三周 Day 3 🎯 今日目标 理解类(class)和对象(object)的关系学会定义类的属性、方法和构造函数(init)掌握对象的创建与使用初识封装、继承和多态的基本概念(预告) &a…...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
