effective C++读书笔记3

news2024/11/15 22:46:13

目录

在资源管理中小心copy行为

在资源管理中提供对原始资源的访问

以独立语句将newed对象置入智能指针


这是effectiveC++中第三章内容:资源管理

在资源管理中小心copy行为

不是所有资源都是heap-based,对那种资源而言,像auto_ptr和 tr1 ::shared_ ptr这样的智能指针往往不适合作为资源掌管者(resource handlers),你需要建立自己的资源管理类。

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

再用一个基于RALL守则的class来管理这个mutex。

例如:

​​​​​​

m12拷贝时会调用lock函数对Mutex对象进行加锁,但是m对象处于使用状态,因为其会阻塞等待,等待m1释放互斥量,但是m1此时也无法向下执行,所以这个程序就产生了死锁,所以对于我们设计的Lock这个类,我们不希望其有拷贝行为。

当RAII对象被复制时,我们通常有以下两种做法

1.禁止复制,当RAII对象被复制并不合理时。

2.对底层资源做引用计数,例如像shared_ptr。

它可以改变mutexPtr的类型,将它从 Mtex*改为tr1 ::shared ptr<Mutex>。然而很不幸tr1 : :shared_ptr的缺省行为是“当引用次数为0时删除其所指物”,我们想要的是解除锁定而不是删除。但shared_ptr是可以提供定制删除器的,也就是析构是怎样的方式去执行。

例如:get函数可以获取内部的原始指针

 再次解释:

1.当引用计数为0时,我们希望做的是解锁资源而不是删除资源,但是我们的shared_ptr提供一个“删除器”,删除器可以是一个函数或函数对象,因此我们为mutexPtr提供了unlokc函数,当引用计数为0时就会调用unlock函数,将Mutex对象解锁。
2.不再设计析构函数:因为默认的析构函数会调用其非静态成员的析构函数,因此默认的析构函数会在互斥器的引用计数为0时自动调用shared_ptr的删除器(此处为unlock函数)
 

请记住:

1.为防止资源泄漏,请使用RAII对象,它们在构造函数中获得资源并在析构函数中释放资源。为防止资源泄漏,请使用Raii对象,它们在构造函数中获得资源并在析构函数中释放资源.

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

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

在资源管理中提供对原始资源的访问

使用智能指针如auto ptr或tr1 : :shared ptr保存factory函数如createInvestment的调用结果。

std::trl ::shared ptr<Investment> pInv (createInvestment());

 该createInvestment()函数会返回一个Investment指针。直接让shared_ptr去管理。

假设你希望以某个函数处理Investment对象,例如:

int daysHeld(const Investment* pi) ;

所以你要将RALL对象中的原始数据拿出来,本例为底部之Investment* ,有显式转换和隐式转换。 显式转换和隐式转换两种做法

显示转换:

tr1 : :shared ptr和 auto_ptr都提供一个get成员函数,用来执行显式转换,也就是它会返回智能指针内部的原始指针(的复件)并且,tr1 : :shared_ptr和 auto_ptr也重载了指针取值(pointer dereferencing)操作符( operator->和operator*),它们允许隐式转换至底部原始指针。

看其中一种做法:

也可在自己创建的RAII类中,写一个get函数。例如:


FontHandle getFont();           //得到某种字体
void releaseFont(FontHandle fh);//释放字体
void changeFontSize(FontHandle f, int newSize); //改变字体大小
 
//FontHandle资源管理类
class Font 
{
public:
    explicit Font(FontHandle fh) :f(fh) {}
    ~Font() { releaseFont(f); }
 
    FontHandle get()const
    {
        return f;
    }
private:
    FontHandle f;
};

API可这使用:

Font f(getFont());
int newFontSize;
 
changeFontSize(f.get(), newFontSize);

另外一种方法是提供隐式转换函数

 隐式转换:

大家可以先看下这篇文章:有详细介绍隐式转换

  • C++:28---类类型转换之类型转换运算符operator(explicit)_董哥的黑板报的博客-CSDN博客_explicit operator

 例如:

  operator FontHandle()const { return f; }

 后面调用函数时会比较自然点:


Font f(getFont());
int newFontSize;
 
//f会自动调用隐式转换函数转换为FontHandle,然后返回类中的FontHandle对象,将其传入参数1
changeFontSize(f, newFontSize);

但这个隐式转换也会增加错误的机会。例如:


Font f1(getFont());
FontHandle f2=f1;

例如下面将f1中的内部资源拷贝给f2,但是如果f1被销毁了,那么f2就称为“虚吊的”(dangle)

 请记住:

1.APIs往往要求访问原始资源(raw resources),所以每一个RAII class应该提供一个“取得其所管理之资源”的办法。API往往要求访问原始资源(原始资源),所以每一个Raii类应该提供一个“取得其所管理之资源”的办法。

2.对原始资源的访问可能经由显式转换或隐式转换。一般而言显式转换比较安全,但隐式转换对客户比较方便。

以独立语句将newed对象置入智能指针

假设我们有个函数用来揭示处理程序的优先权,另一个函数用来在某动态分配所得的 widget上进行某些带有优先权的处理:

int priority();
void processwidget (std::tr1 : :shared_ptr<widget> pw,int priority);

 目前上面这条代码还不能编译通过,tr1 : :shared_ptr构造函数需要一个原始指针(raw pointer),但该构造函数是个explicit构造函数,无法进行隐式转换,将得自"newWidget"的原始指针转换为processwidget所要求的tr1 ::shared_ptr。

例如:

processWidget (std: :tr1: :shared_ _ptr<Widget> (new Widget), priority());

但上述的调用还可能出现资源泄漏的问题。原因:

编译器产出一个processwidget调用码之前,必须首先核算即将被传递的各个实参。上述第二实参只是一个单纯的对priority函数的调用,但第一实参std: :tr1 : : shared_ ptr<Widget>(new widget)由两部分组成:

C++ 编译器以什么样的次序完成这些事情呢?弹性很大。这和其他语言如Java和C#不同,那两种语言总是以特定次序完成函数参数的核算。可以确定的是"newwidget”一定执行于tr1 : :shared ptr构造函数被调用之前,但对priority的调用则可以排在第--或第二或第三执行。若先执行new语句,在执行priority,最后调用构造函数,如果priority出错了,那么资源就泄漏了。

解决方法:避免这类问题就是分离语句,将“创建的对象”与“放入智能指针对象”这两个步骤合成一步完成,而不是在函数调用中完成。

例如:


std::tr1::shared_ptr<Widget> pw(new Widget); //以单独语句存储对象
processWidget(pw, priority()); 

请记住:

1.以独立语句将newed对象存储于(置入)智能指针内。如果不这样做,一旦异常被抛出,有可能导致难以察觉的资源泄漏。
 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C语言进阶】数据在内存的存储

作者:匿名者Unit 目录一.数据类型分类1.整形2.浮点型3.构造类型4.指针类型5.空类型二.整形的存储1.原、反、补码2.大小端存储三.浮点数的存储一.数据类型分类 根据不同的数据类型&#xff0c;在内存中的人存储方法也有所差异&#xff0c;所以我们先来介绍一下数据类型的分类。…

(二)uboot移植--从零开始自制linux掌上电脑(F1C200S)<嵌入式项目>

目录 一、前言 二、F1C200s上电启动顺序 三、前期准备 四、新建用户 五、交叉编译环境配置 六、uboot简介 七、uboot移植 &#x1f34f; uboot下载 &#x1f34f; uboot默认配置 &#x1f34f; uboot图形界面配置 &#x1f34f; uboot编译 &#x1f34f; 烧录bin…

Python-变量和简单数据类型

目录 1. 字符串 1.1. 修改字符串大小写 1.2. 合并字符串 1.3. 制表符与换行符 1.4. 删除空白 2. 数字 2.1. 使用 2.2. 使用str函数避免类型错误 2.3. 注释 2.4. Python之禅 1. 字符串 1.1. 修改字符串大小写 首字母大写&#xff1a;name.title()全部大写&#xf…

基于DDAUNet的CT食管肿瘤分割

摘要 在CT图像中手动或自动描绘食道肿瘤是非常具有挑战性的。这是由于肿瘤与邻近组织的对比度低,食道的解剖结构变化,以及偶尔存在异物(如喂食管)。 本文提出了一种基于卷积神经网络的全自动端到端食管肿瘤,本文所提出的网络称为扩张密集注意力网络,利用每个密集块中的空…

VScode代码片段尝试

最近开始尝试强迫自己使用 VSCode&#xff0c;毕竟 Webstorm 用了很多年了&#xff0c;依赖性比较严重。但是&#xff0c;最近 Webstorm 越来越难搞到免费永久合法使用方式了。 遂转向 VSCode 。 不过 VSCode 需要调教&#xff0c;不像 Webstorm 那么集成度比较高&#xff0c…

CalDAV网络服务器Baikal

什么是 Baikal &#xff1f; Baikal 是一个免费的开源自托管 CalDav 和 CardDav 服务器&#xff0c;适用于想要管理其数据并确保其数据是私有的用户。 Baikal和群晖套件中的 Synology Calendar 是类似的应用&#xff1b; 什么是 CalDav ? CalDav 是一种互联网标准和协议&…

Qt扫盲-QVector理论总结

QVector理论总结一、概述二、使用1. 声明初始化2. 获取元素和链表信息3. 常用操作4. 迭代Vector三、注意一、概述 QVector是Qt的泛型容器类之一。它将每一个元素存储在相邻的内存位置&#xff0c;并提供快速的基于索引的访问。 QList&#xff0c; QLinkedList&#xff0c; QVe…

eurake原理分析以及搭建

消费者随时能够监控到服务的状态 消费者如何获取服务提供者具体的信息&#xff1f; 1&#xff09;服务提供者启动时间eureka注册自己的信息 2&#xff09;eureka保存这些信息 3&#xff09;消费者根据服务名称向eureka拉取提供者的信息 如果有多个服务提供者&#xff0c;消费者…

VS代码生成工具ReSharper v2022.3官宣首发——支持C# 11

实质上&#xff0c;ReSharper特征可用于C#&#xff0c;VB.net&#xff0c;XML&#xff0c;Asp.net&#xff0c;XAML&#xff0c;和构建脚本。 使用ReSharper&#xff0c;你可以进行深度代码分析&#xff0c;智能代码协助&#xff0c;实时错误代码高亮显示&#xff0c;解决方案范…

网络OSI(七层模型)

OSIOSI是一个理论上的网络通信模型&#xff0c;而TCP/IP则是实际运行的网络协议。TCP/IPTCP/IP (传输控制协议/网际协议) 网络通信模型 以及一整个网络传输协议家族应用层应用层协议: FTP TFTP HTTP SNMP SMTP DNS Telnet表示层 数据格式化 代码转换 数据解密/加密会话层 解除或…

低代码如何构建响应式布局前端页面

“你开发的界面为啥在我的屏幕里这么小啊&#xff1f;” “这个界面为啥在我这里会出现横向滚动条啊&#xff1f;” 大家在进行前端界面开发时&#xff0c;有没有遇到这些类似的问题呢&#xff1f;又是如何解决的呢&#xff1f; 页面响应式 在进行项目交付的场景中&#xf…

JavaEE【Spring】:Spring AOP

文章目录一、概念1、定义2、作用二、Spring AOP1、AOP 组成① 切面&#xff08;Aspect&#xff09;② 连接点&#xff08;Join Point&#xff09;③ 切点&#xff08;Pointcut&#xff09;④ 通知&#xff08;Advice&#xff09;2、实现① 添加 AOP 框架支持② 定义切面和切点Ⅰ…

都有哪些好用的设备维护管理软件?这5款值得一试

都有哪些好用的设备维护管理软件&#xff1f; 速速点进来&#xff0c;这些超高性价比的设备维护管理App/软件不容错过&#xff01; 设备是工厂及企业生存的基础&#xff0c;设备的正常运作是保证工厂及企业存活的前提&#xff0c;而要保证设备的正常运作&#xff0c;就必须要…

NLP预训练小结-从词向量到BERT

图像预训练预训练首先是在图像领域广泛应用的。设计网络结构后&#xff0c;处理图像一般是CNN的多层叠加网络结构&#xff0c;先用训练集对网络预先训练&#xff0c;处理新任务时采取相同的网络结构&#xff0c;在比较浅的几层CNN结构&#xff0c;网络参数初始化的时候可以加载…

思科路由器DHCPv6中继服务配置

配置如下&#xff1a; Router>ena Router#conf t Router(config)#host R1 R1(config)#ipv6 unicast-routing R1(config)#service dhcp R1(config)#int g0/1 R1(config-if)#ipv6 add 2001:1::1/64 R1(config-if)#no sh R1(config-if)#exit R1(config)#ipv6 local …

【自学Java】Java三目运算符

Java三目运算符 Java三目运算符教程 在 Java 语言 中&#xff0c;有一种语言可以等价于使用 if…else 进行变量的赋值操作。它就是三目运算符。 Java语言三目运算符详解 语法 Object result condition?value:value2;参数 参数描述condition条件判断符&#xff0c;一般运…

PointNet++详解(二):网络结构解析

如有错误&#xff0c;恳请指出。 在之前对PointNet与PointNet网络进行了介绍&#xff0c;接下来是对其代码的解析。 1. 论文阅读笔记 | 三维目标检测——PointNet 2. 论文阅读笔记 | 三维目标检测——PointNet 参考的github项目为&#xff1a;https://github.com/yanx27/Poi…

window10安装minio

1、首先第一步我们先下载minio 可以从官网上下不同的版本 下载地址&#xff1a;MinIO | Code and downloads to create high performance object storage 2、启动minio 切记不要双击minio&#xff0c; 1、把下载好的minio.exe放到F(我这里放到F里了)&#xff0c;在地址栏里输…

【NI Multisim 14.0编辑环境——项目管理器】

目录 序言 一、项目管理器 ⛄1.“设计工具箱”面板 ⛄2.“SPICE 网表查看器”面板 ⛄3.“LabVIEW 协同仿真终端”面板 序言 NI Multisim最突出的特点之一就是用户界面友好。它可以使电路设计者方便、快捷地使用虚拟元器件和仪器、仪表进行电路设计和仿真。 首先启动NI Mu…

前端调试(常用)

定义调试&#xff1a;代码在某个平台运行&#xff0c;把运行时的状态通过某种方式暴露出来&#xff0c;传递给开发工具做 UI 的展示和交互&#xff0c;辅助开发者排查问题、梳理流程、了解代码运行状态等&#xff0c;这个就是调试。调试就是通过某种信道&#xff08;比如 WebSo…