条款18:让接口容易被正确使用,不易被误用

假设正在为一个表示时间日期的类设计构造函数:

class Date {
public:Date(int month, int day, int year);...
};
Date d(30, 3, 1995); // 糟糕! 应该是 “3, 30” , 而不是 "30, 3"
Date d(2, 30, 1995); // 糟糕! 应该是 "3, 30" , 而不是 "2, 30"

引入新的类型,可以避免许多客户的错误:

struct Day {explicit Day(int d) :val(d) {}int val;
};
struct Month {explicit Month(int d) :val(d) {}int val;
};
struct Year {explicit Year(int d) :val(d) {}int val;
};class Date {
public:Date(const Month& m, const Day& d, const Year& y);...
};Date d(30, 3, 1995); 				// 错误! 参数类型错误
Date d(Day(30), Month(3), Year(1995)); 	// 错误! 参数类型错误
Date d(Month(3), Day(30), Year(1995)); 	// 正确, 参数类型正确

 只有12个有效的月份值,Month类型应该反映这一点。一种方法是使用枚举来表示月份,但枚举的类型安全性不高。例如,枚举可以像int一样使用(参见条款2)。更安全的解决方案是预先定义所有有效月份的集合:

class Month {
public:static Month Jan() { return Month(1); }  static Month Feb() { return Month(2); }  ...  static Month Dec() { return Month(12); }  ... // 其他成员函数
private:explicit Month(int m); // 防止创建新的月份值... // 月份特有的数据
};
Date d(Month::Mar(), Day(30), Year(1995));

任何要求客户小心的接口都容易被错误使用,因为客户可能会忘记:

Investment* createInvestment(); // 来之条款13; 为简单起见,省略了参数

这会导致至少两种类型的客户错误:没有删除指针,以及多次删除同一个指针。
一个更好的接口决策是,让工厂函数返回一个智能指针:

std::shared_ptr<Investment> createInvestment();// 错误!尝试使用自定义删除器创建一个null shared_ptr;
std::shared_ptr<Investment> pInv(0, getRidOfInvestment);std::shared_ptr<Investment> pInv(static_cast<Investment*>(0), getRidOfInvestment); // 可以std::shared_ptr<Investment> createInvestment()
{std::shared_ptr<Investment>    retVal(static_cast<Investment*>(0),getRidOfInvestment);retVal = ...; // 让retVal指向正确的对象return retVal;
}

shared_ptr可以解决“跨DLL问题”。当在一个DLL中使用new创建对象,但在另一个DLL中delete时,会出现此问题。shared_ptr避免了这个问题,因为它的默认删除器来自创建shared_ptr的同一个DLL中。例如,如果Stock是Investment的派生类:

std::shared_ptr<Investment> createInvestment()
{return std::shared_ptr<Investment>(new Stock);
}
  • 好的接口易于正确使用,而不容易错误使用。应该在所有的接口中努力实现这些特性。
  • 促进正确使用的方法包括:接口的一致性和与内置类型的行为兼容性。
  • 防止错误的方法包括创建新类型、限制类型上的操作、限制对象值以及消除客户资源管理责任。
  • shared_ptr支持自定义删除器。这防止了跨dll问题,可以用来自动解锁互斥锁(见条款14)等

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

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

相关文章

游戏美术的技与艺

大家好&#xff0c;我是阿赵。   可能很多朋友都知道&#xff0c;我刚进入游戏行业的时候&#xff0c;做的是美术工作&#xff0c;包括了建模、贴图、动画等&#xff0c;都做过。我对各种美术资源制作也都很熟悉&#xff0c;懂得很多制作的技术。但最后&#xff0c;我却没有继…

李沐-《动手学深度学习》-- 01-预备知识

一、线性代数知识 1. 矩阵计算 a. 矩阵求导 ​ 当y和x分别为标量和向量时候&#xff0c;进行求导得到的矩阵形状&#xff0c;矩阵求导就是矩阵A中的每一个元素对矩阵B中的每一个元素求导 ​ 梯度指向的是值变化最大的方向 ​ 分子布局和分母布局&#xff1a; b. 常识 ax…

美格智能5G RedCap模组SRM813Q通过广东联通5G创新实验室测试认证

近日&#xff0c;美格智能5G RedCap轻量化模组SRM813Q正式通过广东联通5G创新实验室端到端的测试验收&#xff0c;获颁测评证书。美格智能已连续通过业内两家权威实验室的测试认证&#xff0c;充分验证SRM813Q系列模组已经具备了成熟的商用能力&#xff0c;将为智慧工业、安防监…

【漏洞复现】润申信息管理系统SQL注入漏洞

漏洞描述 申信息科技企业标准化管理系统 DefaultHandler.ashx SQL注入漏洞 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#xff0c;不得利用网络从事危害国家安全、荣誉和利益&#x…

.NET某软件非托管泄露分析

一:背景 遇到过很多程序的故障和杀毒软件扯上了关系,有杀毒软件导致的程序卡死,有杀毒软件导致的程序崩溃,这一篇又出现了一个杀毒软件导致的程序非托管内存泄露,真的是分析多了什么鬼都能撞上。 开启了ust并在内存超出预期时抓了一个dump下来,接下来就是分析了。 二:W…

gRCP - 面向未来的第二代 RPC 技术,解析 HTTP2.0 和 Protobuf

目录 一、gRCP - 面向未来的第二代 RPC 技术 1.1、gRPC 简介 1.1.1、gRPC 是个啥&#xff1f; 1.1.2、gRPC 核心设计思路 1.1.3、gRPC 和 ThriftRPC 区别 1.1.4、为什么使用 gRPC&#xff1f;&#xff08;好处&#xff09; 1.2、HTTP2.0 协议 1.2.1、回顾 HTTP1.0 和 H…

数据结构-怀化学院期末题

希尔排序 题目&#xff1a; 利用希尔排序算法实现线性表的排序。希尔排序是根据给定的增量序列将线性表分隔成某个“增量”的记录组成一个子序例&#xff0c;在子序列中采用直接插入排序完成。 输入 第一行为元素个数n(1<n<1000)&#xff0c;第二行为n个元素值(整数)&am…

【C++】带你学会使用C++线程库thread、原子库atomic、互斥量库mutex、条件变量库condition_variable

C线程相关知识讲解 前言正式开始C官方为啥要提供线程库thread构造函数代码演示this_threadget_id()yield()sleep_until和sleep_for mutex构造函数lock和unlock上锁全局锁局部锁lambda表达式 try_lock 其他锁时间锁递归版本专用锁recursive_mutex 锁的异常处理lock_guardunique_…

Linux_CentOS_7.9_Oracle11gr2配置数据库及监听服务自启动多方案实操之简易记录

前言: 作为运维保障,都无法准确预估硬件宕机的突发阶段,其生产数据实时在产出,那作为dba数据库服务以及相关Listener的其重要性、必要性就突显而出。这里拿虚拟机试验做个配置记录,便于大家学习参考。 实现方法一: 环境变量值::$ORACLE_HOME= /data/oracle/product/1…

逆向一个Go程序

前奏 事先声明&#xff0c;自导自演&#xff0c;纯属为了演示基本的逆向思维 用Go写一段模拟登录的代码&#xff1a; package mainimport ("fmt" )func main() {pass : ""fmt.Print("input password:")fmt.Scan(&pass)if pass "hel…

包管理

moment —解析,校验,操作日期的第三方包 在项目中安装和使用包 1. 安装npm install 包的完整名称---可以简写为npm i 完整包的名称2. 导入包require(包名称)3. 查看官方文档初次装包完成后,在项目文件夹下多了一个node_modules文件夹和package-lock.json的配置文件. node_modu…

【极客日常】慢查询的风险治理思路

在线上环境运维过程中&#xff0c;我们通常需要治理慢查询的风险。慢查询会引起DB性能问题&#xff0c;并且当线上环境流量较大的情况下&#xff0c;就会出现因大量慢查询堆积导致DB被打挂的情况。因此&#xff0c;本篇文章分享一下慢查询的风险治理思路。 首先&#xff0c;我…

Matlab二维绘图

低级绘图命令line 有什么点就点哪里&#xff0c;然后连起来&#xff0c;没什么细节&#xff0c;不光滑&#xff0c;所以基本不会用到。 x0:0.2*pi:2*pi; ysin(x); line(x,y);%画一条sin函数线 line([-5,5],[2,2]);%画一条水平线 line([5,5],[0,2]);%画一条竖线 高级绘图命令…

一文搞懂MCU RAM的分配

一文搞懂MCU RAM的分配 文章目录 一文搞懂MCU RAM的分配1. 前言2. 数据段含义2.1 Program Size解析 3. 局部变量、全局变量、常量如何占用 RAM?3.1 栈大小Stack_Size 与 堆大小Heap_Size3.2 验证栈大小设置&#xff0c;对程序编译的影响3.3 验证局部变量RAM分配3.4 验证全局变…

Mac系统安装PicGo时打开报错:文件已损坏

目录 一、前言二、解决方案三、结尾 一、前言 我们在安装某些第三方开发者开发的应用时&#xff0c;无法在 Mac 上运行&#xff0c;提示已经损坏&#xff0c;报以下错误&#xff1a;Mac系统安装PicGo时打开报错&#xff1a;文件已损坏&#xff0c;您应该将它移到废纸篓 二、解决…

LeetCode 2807.在链表中插入最大公约数

【LetMeFly】2807.在链表中插入最大公约数 力扣题目链接&#xff1a;https://leetcode.cn/problems/insert-greatest-common-divisors-in-linked-list/ 给你一个链表的头 head &#xff0c;每个结点包含一个整数值。 在相邻结点之间&#xff0c;请你插入一个新的结点&#x…

DQL命令查询数据(三)

本课目标 掌握MySQL的多表查询 SQL语句的综合应用 多表连接查询 通过各个表之间共同列的关联性&#xff08;例如&#xff1a;外键&#xff09;来查询的 分类&#xff1a; 内连接(INNER JOIN) &#xff0c;可简写为 JOIN&#xff1b;左外连接(LEFT OUTER JOIN)&#xff0c;…

Java技术栈 —— Hadoop入门(一)

Java技术栈 —— Hadoop入门&#xff08;一&#xff09; 一、Hadoop第一印象二、安装Hadoop三、Hadoop解析3.1 Hadoop生态介绍3.1.1 MapReduce - 核心组件3.1.2 HDFS - 核心组件3.1.3 YARN - 核心组件3.1.4 其它组件3.1.4.1 HBase3.1.4.2 Hive3.1.4.3 Spark 一、Hadoop第一印象…

【Project】TPC-Online Module (manuscript_2024-01-07)

PRD正文 一、概述 本模块实现隧道点云数据的线上汇总和可视化。用户可以通过注册和登录功能进行身份验证&#xff0c;然后上传原始隧道点云数据和经过处理的数据到后台服务器。该模块提供数据查询、筛选和可视化等操作&#xff0c;同时支持对指定里程的分段显示和点云颜色更改…

小游戏实战丨基于PyGame的消消乐小游戏

文章目录 写在前面PyGame消消乐注意事项系列文章写在后面 写在前面 本期内容&#xff1a;基于pygame实现喜羊羊与灰太狼版消消乐小游戏 下载地址&#xff1a;https://download.csdn.net/download/m0_68111267/88700193 实验环境 python3.11及以上pycharmpygame 安装pygame…