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

Effective C++ 学习笔记 条款14 在资源管理类中小心copying行为

条款13导入这样的观念:“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization,RAII),并以此作为“资源管理类”的脊柱,也描述了auto_ptr和tr1::shared_ptr如何将这个观念表现在heap-based资源上。然而并非所有资源都是heap-based,对那种资源而言,像auto_ptr和tr1::shared_ptr这样的智能指针往往不适合作为资源掌管者(resource handlers)。既然如此,有可能偶尔你会发现,你需要建立自己的资源管理类。

例如,假设我们使用C API函数处理类型为Mutex的互斥器对象(mutex objects),共有lock和unlock两函数可用:

void lock(Mutex *pm);    // 锁定pm所指的互斥器
void unlock(Mutex *pm);    // 将互斥器解除锁定

为确保绝对不会忘记将一个被锁住的Mutex解锁,你可能会希望建立一个class用来管理锁。这样的class的基本结构由RAII守则支配,也就是“资源在构造期间获得,在析构期间释放”:

class Lock
{
public:explicit Lock(Mutex &pm) : mutexPtr(pm){lock(mutexPtr);    // 获得资源}~Lock(){unlock(mutexPtr);    // 释放资源}private:Mutex *mutexPtr;
};

客户对Lock的用法符合RAII方式:

Mutex m;    // 定义你需要的互斥器
// ...
{    // 建立一个区块用来定义critical sectionLock ml(&m);    // 锁定互斥器// ...    执行critical section内的操作
}    // 在区块最末尾,自动解除互斥器锁定

这很好,但如果Lock对象被复制,会发生什么事?

Lock m11(&m);    // 锁定m
Lock ml2(ml1);    // 将ml1复制到ml2身上,这会发生什么事?

这是某个一般化问题的特定例子。那个一般化问题是每位RAII class作者一定需要面对的:“当一个RAII对象被复制,会发生什么事?”大多数时候你会选择以下两种可能:
1.禁止复制。许多时候允许RAII对象被复制并不合理。对一个像Lock这样的class这是有可能的,因为很少能够合理拥有synchronization primitives的副本。如果复制动作对RAII class并不合理,你便应该禁止之。条款6告诉你怎么做:将copying操作声明为private。对Lock而言看起来是这样:

class Lock : private Uncopyable    // 禁止复制,见条款6
{
public:// ...    如前
};

2.对底层资源祭出“引用计数法”(reference-count)。有时候我们希望保有资源,直到它的最后一个使用者(某对象)被摧毁。这种情况下复制RAII对象时,应该将资源的“被引用数”递增。tr1::shared_ptr便是如此。

通常只要内含一个tr1::shared_ptr成员变量,RAII class便可实现出reference-counting copying行为。如果前述的Lock打算使用reference counting,它可以改变mutexPtr的类型,将它从Mutex *改为tr1::shared_ptr<Mutex>。然而很不幸tr1::shared_ptr的缺省行为是“当引用次数为0时删除其所指物”,那不是我们所要的行为。当我们用上一个Mutex,我们想要做的释放动作是解除锁定而非删除。

幸运的是tr1::shared_ptr允许指定所谓的“删除器”(deleter),那是一个函数或函数对象(function object),当引用次数为0时便被调用(此机能并不存在于auto_ptr——它总是将其指针删除)。删除器对tr1::shared_ptr构造函数而言是可有可无的第二参数,所以代码看起来像这样:

class Lock
{
public:explicit Lock(Mutex *pm) : mutexPtr(pm, unlock)    // 以某个Mutex初始化shared_ptr,并以unlock函数为删除器{lock(mutexPtr.get());    // 条款15谈到“get”,它会返回存储的指针}private:std::tr1::shared_ptr<Mutex> mutexPtr;    // 使用shared_ptr替换raw pointer
};

请注意,本例的Lock class不再声明析构函数。因为没有必要。条款5说过,class析构函数(无论是编译器生成的,或用户自定的)会自动调用其non-static成员变量(本例为mutexPtr)的析构函数。而mutexPtr的析构函数会在互斥器的引用计数为0时自动调用tr1::shared_ptr的删除器(本例为unlock)(当你阅读这个class的原始码,或许会感谢其中有一条注释指出:你并没有忘记析构,你只是倚赖了编译器生成的缺省行为)。

3.复制底部资源。有时候,只要你喜欢,可以针对一份资源拥有其任意数量的副本。而你需要“资源管理类”的唯一理由是,当你不再需要某个副本时确保它被释放。在此情况下复制资源管理对象,应该同时也复制其所包覆的资源。即,复制资源管理对象时,进行的是“深度拷贝”。

某些标准字符串类型是由“指向heap内存”的指针构成(那内存被用来存放字符串的组成字符)。这种字符串对象内含一个指针指向一块heap内存。当这样一个字符串对象被复制,不论指针或其所指内存都会被制作出一个副本。这样的字符串展现深度复制(deep copying)行为。

4.转移底部资源的拥有权。某些罕见场合下你可能希望确保永远只有一个RAII对象指向一个未加工资源(raw resource),即使RAII对象被复制依然如此。此时资源的拥有权会从被复制物转移到目标物。一如条款13所述,这是auto_ptr奉行的复制意义。

copying函数(包括copy构造函数和copy assignment操作符)有可能被编译器自动创建出来,因此除非编译器生成版本做了你想要做的事(条款5提过其缺省行为),否则你得自己编写它们。某些情况下你或许也想支持这些函数的一般版本(指模板函数),这样的版本描述于条款45。

请记住:
1.复制RAII对象必须一并复制它所管理的资源,所以资源的copying行为决定RAII对象的copying行为。

2.普遍而常见的RAII class copying行为是:抑制copying、施行引用计数法(reference counting)。不过其他行为也都可能被实现。

相关文章:

Effective C++ 学习笔记 条款14 在资源管理类中小心copying行为

条款13导入这样的观念&#xff1a;“资源取得时机便是初始化时机”&#xff08;Resource Acquisition Is Initialization&#xff0c;RAII&#xff09;&#xff0c;并以此作为“资源管理类”的脊柱&#xff0c;也描述了auto_ptr和tr1::shared_ptr如何将这个观念表现在heap-base…...

c++数据结构算法复习基础-- 3 --线性表-单向链表-笔试面试常见问题

1、单链表逆序 思路图 代码实现 //著: 链表结构里记得加 friend void ReverseLink(Clink& link); void ReverseLink(Clink& link) {Node* p link.head_->next_;while( p nullptr){return;}Node* q p->next_;link.head_->next_ nullptr;while(p ! nullpt…...

【踩坑专栏】追根溯源,从Linux磁盘爆满排查故障:mycat2与navicat不兼容导致日志暴增

昨天遇到了一个比较奇怪的问题&#xff0c;就是在挂起虚拟机的时候&#xff0c;虚拟机提示我XX脚本正在运行&#xff0c;很奇怪&#xff0c;我没有运行脚本&#xff0c;为什么会提示我这个呢。今天恢复虚拟机&#xff0c;也提示了一下脚本的问题&#xff0c;而且发现Linux明显异…...

DolphinScheduler——奇富科技的调度实践

目录 一、技术架构 二、业务挑战 2.1 调度任务量大 2.2 运维复杂 2.3 SLA要求高 三、调度优化实践 3.1 重复调度 3.2 漏调度 3.3 Worker服务卡死 3.4 任务重复运行 四、服务监控 4.1 方法耗时监控 4.2 任务调度链路监控 五、用户收益 原文大佬的这篇调度系统案例…...

2024年最全洗地机选购攻略盘点丨希亦、小米、云鲸、海尔洗地机哪款值得入手?

在现代家居清洁中&#xff0c;洗地机是不可或缺的得力助手&#xff0c;它融合了吸尘、拖地等多种功能。面对市场上琳琅满目的洗地机品牌和型号&#xff0c;选择一个可靠的品牌至关重要。优质的品牌能够提供高品质的产品&#xff0c;使您的清洁工作更加轻松高效。本文将向您推荐…...

HTML笔记3

21&#xff0c;label标签 <label for"...">...</label> <label>...</label> <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content&qu…...

利用Python副业赚钱,看完这篇你就懂了!

Python都可以做哪些副业&#xff1f; 1、兼职处理数据Excel整理数据功能虽然很强大&#xff0c;但在Python面前&#xff0c;曾经统治职场的它也的败下阵来。因为Python在搜集数据整理分析数据的过程中更加便捷&#xff0c;通过几行代码还可以实现自动化操作。 如果你学会Pyth…...

FP16(半精度浮点数)、FP32(单精度浮点数)和INT8

在深度学习和计算机视觉领域中&#xff0c;FP16&#xff08;半精度浮点数&#xff09;、FP32&#xff08;单精度浮点数&#xff09;和INT8&#xff08;8 位整数&#xff09;是常见的数据类型或精度表示方式。它们在不同的场景下有各自的优势和用途。 FP16&#xff08;半精度浮…...

MySQL数据管理二

1.数据库的完整性 数据库中的数据是从外界输入的&#xff0c;而数据的输入由于种种原因&#xff0c;会发生输入无效或错误信息。保证输入的数据符合规定&#xff0c;成为了数据库系统&#xff0c;尤其是多用户的关系数据库系统首要关注的问题。 它是应防止数据库中存在不符合语…...

sqoop-import 详解

文章目录 前言一、介绍1. sqoop简介2. sqoop import的作用3. 语法3.1 sqoop import 语法3.2 导入配置属性 二、导入参数1. 常见参数2. 验证参数3. 导入控制参数4. 用于覆盖映射的参数5. 增量导入参数6. 输出行格式参数7. 输入解析参数8. Hive 参数9. HBase 参数10. Accumulo 参…...

第二周opencv

一、边缘检测算子 边缘检测算子是用于检测图像中物体边界的工具。边缘通常表示图像中灰度值或颜色发生显著变化的地方。边缘检测有助于识别图像中的物体形状、轮廓和结构。这些算子通过分析图像的灰度或颜色梯度来确定图像中的边缘。 梯度算子 要得到一幅图像的梯度&#xff0c…...

python_读取txt文件绘制多条曲线II

从给定的列表中来匹配txt文件对应列的数据&#xff1b; import matplotlib.pyplot as plt import re from datetime import datetime from pylab import mplmpl.rcParams["font.sans-serif"] ["SimHei"] # 设置显示中文字体 mpl.rcParams["axes.un…...

java排序简单总结和推荐使用套路(数据排序,结构体排序)

了解int和Integer的区别 int是Java的基本数据类型&#xff0c;用于表示整数值。Integer是int的包装类&#xff0c;它是一个对象&#xff0c;可以包含一个int值并提供一些额外的功能。 Java集合框架中的集合类&#xff08;如List、Set、Map&#xff09;只能存储对象&#xff0c;…...

掘根宝典之C语言联合和枚举

联合 C语言中的联合&#xff08;Union&#xff09;是一种特殊的数据类型&#xff0c;它允许在同一块内存空间中存储不同类型的数据。 联合与结构体类似&#xff0c;但不同的是&#xff0c;在给联合变量赋值时&#xff0c;它只能存储最后一次赋值的值。 创建联合 在C语言中&…...

【debug】element-ui时间控件回显后不可编辑且显示为空

问题&#xff1a;使用element-ui的时间控件回显数据&#xff0c;编辑数据没有反应&#xff1a;点时间和“确认”按钮都没反应。 输入框中会显示数据&#xff0c;但提交时的校验显示为空。 <el-form-item label"开始时间" prop"limitStartTime"><…...

【Linux从青铜到王者】进程信号

——————————————————————————————————————————— 信号入门 在了解信号之前有许多要理解的相关概念 我们可以先通过一个生活例子来初步认识一下信号 1.生活角度的信号 你在网上买了很多件商品&#xff0c;再等待不同商品快递的到来…...

MyBatis-Plus 快速入门

介绍 j​​​​​MyBatis-Plus (opens new window)&#xff08;简称 MP&#xff09;是一个 MyBatis (opens new window)的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 官网&#xff1a;MyBatis-Plus (baomidou.com) 1.…...

iOS调起高德/百度/腾讯/谷歌/苹果地图并使用GCJ02坐标进行导航

使用演示: 2.地图API相关网站 : 高德:...

HarmonyOS Full SDK的安装

OpenHarmony的应用开发工具HUAWEI DevEco Studio现在随着OpenHarmony版本发布而发布,只能在版本发布说明中下载,例如最新版本的OpenHarmony 4.0 Release。对应的需要下载DevEco Studio 4.0 Release,如下图。 图片 下载Full SDK主要有两种方式,一种是通过DevEco Studio下载…...

小程序嵌套H5-真机突然无法使用

今天测试反馈了一个问题&#xff0c;测试环境的小程序突然就登录不了了。我自己拿手机扫码登录是正常的&#xff0c;用其他同事的手机扫描登录也是正常。 下面是排查的路线&#xff1a; 1、其他环境使用测试手机扫码登录是否正常&#xff1f;(正常) 2、H5地址改为本地IP&#…...

从零构建:基于YOLOv8/YOLOv10的智能游戏瞄准系统深度解析

从零构建&#xff1a;基于YOLOv8/YOLOv10的智能游戏瞄准系统深度解析 【免费下载链接】yolov8_aimbot Aim-bot based on AI for all FPS games 项目地址: https://gitcode.com/gh_mirrors/yo/yolov8_aimbot 你是否曾经好奇&#xff0c;人工智能技术如何精准识别游戏中的…...

仅剩最后47份!《Midjourney概念艺术创作密钥手册》(含23个受版权保护的材质编码+动态光照参数表)

更多请点击&#xff1a; https://codechina.net 第一章&#xff1a;《Midjourney概念艺术创作密钥手册》核心价值与版权说明 核心价值定位 本手册聚焦于概念艺术创作中“意图—提示—反馈—迭代”的闭环实践&#xff0c;提炼出可复用的提示工程范式、风格锚定策略与跨模态语义…...

别再死记硬背了!用这5个真实案例,彻底搞懂NumPy的einsum函数

别再死记硬背了&#xff01;用这5个真实案例&#xff0c;彻底搞懂NumPy的einsum函数 当你第一次看到np.einsum(ij,jk->ik, A, B)这样的表达式时&#xff0c;是不是感觉像在破译外星密码&#xff1f;作为NumPy中最强大却也最令人困惑的函数之一&#xff0c;einsum&#xff08…...

终极指南:如何彻底禁用iPhone过热降频,告别游戏卡顿和屏幕变暗

终极指南&#xff1a;如何彻底禁用iPhone过热降频&#xff0c;告别游戏卡顿和屏幕变暗 【免费下载链接】thermalmonitordDisabler A tool used to disable iOS daemons. 项目地址: https://gitcode.com/gh_mirrors/th/thermalmonitordDisabler 你是否在玩高画质游戏时突…...

pdf2pptx:打破学术演示壁垒的智能转换神器

pdf2pptx&#xff1a;打破学术演示壁垒的智能转换神器 【免费下载链接】pdf2pptx Convert your (Beamer) PDF slides to (Powerpoint) PPTX 项目地址: https://gitcode.com/gh_mirrors/pd/pdf2pptx 你是否曾因LaTeX Beamer制作的精美数学公式幻灯片无法在PowerPoint中完…...

DMA链表模式(LLI)实战:如何用一块内存搞定不连续地址的数据搬运?

DMA链表模式(LLI)实战&#xff1a;如何用一块内存搞定不连续地址的数据搬运&#xff1f; 在物联网和通信系统的开发中&#xff0c;我们经常遇到需要从多个分散的数据源收集信息&#xff0c;或将数据分发到不同目标地址的场景。比如一个智能家居网关需要同时处理来自温湿度传感…...

贝壳季报图解:营收189亿 经调整净利16亿同比增15.7%

雷递网 雷建平 5月19日贝壳&#xff08;纽交所代码&#xff1a;BEKE&#xff1b;香港联交所代号&#xff1a;2423&#xff09;今日公布其截至2026年3月31日止第一季度未经审计财务业绩。财报显示&#xff0c;贝壳2026年第一季度贝壳实现净收入189亿元&#xff0c;净利润12.55亿…...

高斯过程回归预测:从“黑箱”到“白盒”,手把手教你用sklearn调参与可视化

高斯过程回归实战&#xff1a;从数学原理到工业级调优指南 金融时序预测中&#xff0c;当业务方质疑模型给出的波动区间时&#xff0c;工程师该如何解释那条逐渐收窄的置信带&#xff1f;设备剩余寿命预测场景下&#xff0c;为什么修改length_scale参数会显著改变退化曲线的拐点…...

自动化 Vue 3 转 React 编译工具 VuReact 连续迭代,全量编译速度提升 30%-40%

近期&#xff0c;自动化 Vue 3 转 React 编译工具 VuReact 完成 v1.8.0、v1.8.1、v1.8.3 连续迭代&#xff0c;围绕性能、稳定性、开发体验深度优化&#xff0c;降低 Vue 项目向 React 迁移门槛。更新聚焦三大方向本轮更新围绕性能、稳定性、开发体验三大方向进行深度优化。尤其…...

嵌入式Linux驱动开发pinctrl篇(1)——从寄存器到子系统:驱动演进之路

嵌入式Linux驱动开发pinctrl篇&#xff08;1&#xff09;——从寄存器到子系统&#xff1a;驱动演进之路 仓库已经开源&#xff01;所有教程&#xff0c;主线内核移植&#xff0c;跑新版本imx-linux/uboot都在这里&#xff0c;或者一起来尝试跑7.0的Linux&#xff01;欢迎各位大…...