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导入这样的观念:“资源取得时机便是初始化时机”(Resource Acquisition Is Initialization,RAII),并以此作为“资源管理类”的脊柱,也描述了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不兼容导致日志暴增
昨天遇到了一个比较奇怪的问题,就是在挂起虚拟机的时候,虚拟机提示我XX脚本正在运行,很奇怪,我没有运行脚本,为什么会提示我这个呢。今天恢复虚拟机,也提示了一下脚本的问题,而且发现Linux明显异…...
DolphinScheduler——奇富科技的调度实践
目录 一、技术架构 二、业务挑战 2.1 调度任务量大 2.2 运维复杂 2.3 SLA要求高 三、调度优化实践 3.1 重复调度 3.2 漏调度 3.3 Worker服务卡死 3.4 任务重复运行 四、服务监控 4.1 方法耗时监控 4.2 任务调度链路监控 五、用户收益 原文大佬的这篇调度系统案例…...
2024年最全洗地机选购攻略盘点丨希亦、小米、云鲸、海尔洗地机哪款值得入手?
在现代家居清洁中,洗地机是不可或缺的得力助手,它融合了吸尘、拖地等多种功能。面对市场上琳琅满目的洗地机品牌和型号,选择一个可靠的品牌至关重要。优质的品牌能够提供高品质的产品,使您的清洁工作更加轻松高效。本文将向您推荐…...
HTML笔记3
21,label标签 <label for"...">...</label> <label>...</label> <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content&qu…...
利用Python副业赚钱,看完这篇你就懂了!
Python都可以做哪些副业? 1、兼职处理数据Excel整理数据功能虽然很强大,但在Python面前,曾经统治职场的它也的败下阵来。因为Python在搜集数据整理分析数据的过程中更加便捷,通过几行代码还可以实现自动化操作。 如果你学会Pyth…...
FP16(半精度浮点数)、FP32(单精度浮点数)和INT8
在深度学习和计算机视觉领域中,FP16(半精度浮点数)、FP32(单精度浮点数)和INT8(8 位整数)是常见的数据类型或精度表示方式。它们在不同的场景下有各自的优势和用途。 FP16(半精度浮…...
MySQL数据管理二
1.数据库的完整性 数据库中的数据是从外界输入的,而数据的输入由于种种原因,会发生输入无效或错误信息。保证输入的数据符合规定,成为了数据库系统,尤其是多用户的关系数据库系统首要关注的问题。 它是应防止数据库中存在不符合语…...
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
一、边缘检测算子 边缘检测算子是用于检测图像中物体边界的工具。边缘通常表示图像中灰度值或颜色发生显著变化的地方。边缘检测有助于识别图像中的物体形状、轮廓和结构。这些算子通过分析图像的灰度或颜色梯度来确定图像中的边缘。 梯度算子 要得到一幅图像的梯度,…...
python_读取txt文件绘制多条曲线II
从给定的列表中来匹配txt文件对应列的数据; 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的基本数据类型,用于表示整数值。Integer是int的包装类,它是一个对象,可以包含一个int值并提供一些额外的功能。 Java集合框架中的集合类(如List、Set、Map)只能存储对象,…...
掘根宝典之C语言联合和枚举
联合 C语言中的联合(Union)是一种特殊的数据类型,它允许在同一块内存空间中存储不同类型的数据。 联合与结构体类似,但不同的是,在给联合变量赋值时,它只能存储最后一次赋值的值。 创建联合 在C语言中&…...
【debug】element-ui时间控件回显后不可编辑且显示为空
问题:使用element-ui的时间控件回显数据,编辑数据没有反应:点时间和“确认”按钮都没反应。 输入框中会显示数据,但提交时的校验显示为空。 <el-form-item label"开始时间" prop"limitStartTime"><…...
【Linux从青铜到王者】进程信号
——————————————————————————————————————————— 信号入门 在了解信号之前有许多要理解的相关概念 我们可以先通过一个生活例子来初步认识一下信号 1.生活角度的信号 你在网上买了很多件商品,再等待不同商品快递的到来…...
MyBatis-Plus 快速入门
介绍 jMyBatis-Plus (opens new window)(简称 MP)是一个 MyBatis (opens new window)的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。 官网: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-真机突然无法使用
今天测试反馈了一个问题,测试环境的小程序突然就登录不了了。我自己拿手机扫码登录是正常的,用其他同事的手机扫描登录也是正常。 下面是排查的路线: 1、其他环境使用测试手机扫码登录是否正常?(正常) 2、H5地址改为本地IP&#…...
黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门 相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
《C++ 模板》
目录 函数模板 类模板 非类型模板参数 模板特化 函数模板特化 类模板的特化 模板,就像一个模具,里面可以将不同类型的材料做成一个形状,其分为函数模板和类模板。 函数模板 函数模板可以简化函数重载的代码。格式:templa…...
Linux系统部署KES
1、安装准备 1.版本说明V008R006C009B0014 V008:是version产品的大版本。 R006:是release产品特性版本。 C009:是通用版 B0014:是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存:1GB 以上 硬盘…...
水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关
在水泥厂的生产流程中,工业自动化网关起着至关重要的作用,尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关,为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多,其中不少设备采用Devicenet协议。Devicen…...
【深度学习新浪潮】什么是credit assignment problem?
Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
WebRTC调研
WebRTC是什么,为什么,如何使用 WebRTC有什么优势 WebRTC Architecture Amazon KVS WebRTC 其它厂商WebRTC 海康门禁WebRTC 海康门禁其他界面整理 威视通WebRTC 局域网 Google浏览器 Microsoft Edge 公网 RTSP RTMP NVR ONVIF SIP SRT WebRTC协…...
