网站自动优化怎么样/郑州seo团队
有许多种做法可以记录时间,因此,设计一个TimeKeeper base class和一些derived classes 作为不同的计时方法,相当合情合理:
class TimeKeeper {
public:TimeKeeper();~TimeKeeper();// ...
};class AtomicClock: public TimeKeeper { }; // 原子钟
class WaterClock: public TimeKeeper { }; // 水钟
class WristWatch: public TimeKeeper { }; // 腕表
许多客户只想在程序中使用时间,不想操心时间如何计算等细节,这时候我们可以设计factory (工厂)函数,返回指针指向一个计时对象。Factory函数会“返回一个base class 指针,指向新生成之 derived class对象”:
TimeKeeper* getTimeKeeper(); // 返回一个指针,指向一个// TimeKeeper派生类动态分配的对象
为遵守factory函数的规矩,被getTimeKeeper()返回的对象必须位于heap。因此为了避免泄漏内存和其他资源,将factory函数返回的每一个对象适当地delete掉很重要:
TimeKeeper* ptk = getTimeKeeper();// ...delete ptk;
条款13说“倚赖客户执行delete动作,基本上便带有某种错误倾向”,条款18则谈到factory函数接口该如何修改以便预防常见之客户错误,但这些在此都是次要的,因为此条款内我们要对付的是上述代码的一个更根本弱点:纵使客户把每一件事都做对了,仍然没办法知道程序如何行动。
问题出在getTimeKeeper返回的指针指向一个derived class对象(例如AtomicClock),而那个对象却经由一个base class指针(例如一个TimeKeeper*指针)被删除,而目前的base class ( TimeKeeper)有个non-virtual析构函数。
这是一个引来灾难的秘诀,因为C++明白指出,当derived class对象经由一个base class指针被删除,而该base class带着一个non-virtual析构函数,其结果未有定义———实际执行时通常发生的是对象的derived成分没被销毁。如果getTimeKeeper返回指针指向一个AtomicClock 对象,其内的 AtomicClock 成分(也就是声明于Atomicclock class内的成员变量)很可能没被销毁,而AtomicClock的析构函数也未能执行起来。然而其base class成分(也就是TimeKeeper这一部分)通常会被销毁,于是造成一个诡异的“局部销毁”对象。这可是形成资源泄漏、败坏之数据结构、在调试器上浪费许多时间的绝佳途径喔。
消除这个问题的做法很简单:给base class一个virtual析构函数。此后删除derive dclass对象就会如你想要的那般。是的,它会销毁整个对象,包括所有derived class成分:
class TimeKeeper {
public:TimeKeeper();virtual ~TimeKeeper();// ...
};TimeKeeper* ptk = getTimeKeeper();// ...delete ptk;
像TimeKeeper这样的base classes除了析构函数之外通常还有其他virtual函数,因为 virtual函数的目的是允许derived class 的实现得以客制化(见条款34)。例如TimeKeeper就可能拥有一个virtual getcurrentTime,它在不同的derived classes 中有不同的实现码。任何 class只要带有 virtual函数都几乎确定应该也有一个virtual析构函数。
如果class 不含virtual函数,通常表示它并不意图被用做一个base class。当class不企图被当作 base class,令其析构函数为virtual往往是个嫂主意。考虑一个用来表示二维空间点坐标的class:
馊主意???
class Point {
public:Point(int xCoord, int yCoord);~Point();private:int x, y;
};
如果int占用32 bits,那么Point对象可塞入一个64-bit缓存器中。更有甚者,这样一个Point对象可被当做一个“64-bit 量”传给以其他语言如C或FORTRAN撰写的函数。然而当Point的析构函数是virtual,形势起了变化。
欲实现出 virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。这份信息通常是由一个所谓vptr ( virtual table pointer)指针指出。 vptr指向一个由函数指针构成的数组,称为vtbl( virtual table);每一个带有 virtual函数的class 都有一个相应的vtbl。当对象调用某一virtual函数,实际被调用的函数取决于该对象的vptr所指的那个vtbl—编译器在其中寻找适当的函数指针。
多了虚函数表
virtual函数的实现细节不重要。重要的是如果Point class内含virtual函数,其对象的体积会增加:在32-bit计算机体系结构中将占用64 bits (为了存放两个ints)至96 bits(两个ints加上 vptr);在64-bit计算机体系结构中可能占用64~128 bits,因为指针在这样的计算机结构中占64 bits。因此,为 Point添加一个vptr会增加其对象大小达50%~100%,Point对象不再能够塞入一个64-bit缓存器,而C++的Point对象也不再和其他语言(如C)内的相同声明有着一样的结构(因为其他语言的对应物并没有 vptr),因此也就不再可能把它传递至(或接受自)其他语言所写的函数,除非你明确补偿vptr—一那属于实现细节,也因此不再具有移植性。
因此,无端地将所有 classes的析构函数声明为virtual,就像从未声明它们为virtual一样,都是错误的。许多人的心得是:只有当class内含至少一个virtual函数,才为它声明virtual析构函数。
即使class完全不带virtual函数,被“non-virtual析构函数问题”给咬伤还是有可能的。举个例子,标准string不含任何virtual函数,但有时候程序员会错误地把它当做base class:
class SpecialString: public std::string {// 馊主意。std::string有个非虚的析构函数
};
乍看似乎无害,但如果你在程序任意某处无意间将一个pointer-to-SpecialString转换为一个pointer-to-string,然后将转换所得的那个string 指针 delete掉,你立刻被流放到“行为不明确”的恶地上:
将子类指针转换成父类指针,让后delete掉
Specialstring* pss = new Specialstring ("Impending Doom");
std::string* ps;ps = pss; // Specialstring* =》 std::string*delete ps;//未有定义!现实中*ps的 Specialstring资源会泄漏,//因为SpecialString析构函数没被调用。
相同的分析适用于任何不带virtual析构函数的 class,包括所有STL容器如vector, list,set, tr1 : : unordered_map(见条款54)等等。如果你曾经企图继承一个标准容器或任何其他“带有non-virtual析构函数”的class,拒绝诱惑吧!(很不幸C+没有提供类似Java的final classes或C#的sealed classes那样的“禁止派生”机制。)
有时候令class带一个pure virtual析构函数,可能颇为便利。还记得吗, pure virtual函数导致abstract(抽象)classes -—也就是不能被实体化(instantiated)的class。也就是说,你不能为那种类型创建对象。然而有时候你希望拥有抽象class,但手上没有任何pure virtual函数,怎么办?唔,由于抽象class总是企图被当作一个base class来用,而又由于base class应该有个virtual析构函数,并且由于pure virtual函数会导致抽象class,因此解法很简单:为你希望它成为抽象的那个class声明一个pure virtual析构函数。下面是个例子:
class AWOV {
public:virtual ~AWOV() = 0; // 纯析构函数};
这个class有一个pure virtual函数,所以它是个抽象class,又由于它有个virtual析构函数,所以你不需要担心析构函数的问题。然而这里有个窍门:你必须为这个pure virtual析构函数提供一份定义:
AwOV:: ~AWOV() { } //pure virtual析构函数的定
第一次知道要这样。
析构函数的运作方式是,最深层派生( most derived)的那个class其析构函数最先被调用,然后是其每一个base class的析构函数被调用。编译器会在 AWov的derivedclasses的析构函数中创建一个对~AWOV的调用动作,所以你必须为这个函数提供一份定义。如果不这样做,连接器会发出抱怨。
“给base classes一个 virtual析构函数”,这个规则只适用于polymorphic(带多态性质的)base classes身上。这种base classes的设计目的是为了用来“通过base class接口处理derived class对象”。TimeKeeper就是一个polymorphic base class,因为我们希望处理AtomicClock和 waterClock对象,纵使我们只有TimeKeeper 指针指向它们。
并非所有base classes的设计目的都是为了多态用途。例如标准string和STL容器都不被设计作为base classes使用,更别提多态了。某些classes的设计目的是作为base classes 使用,但不是为了多态用途。这样的classes 如条款6的Uncopyable和标准程序库的input_iterator_tag(条款47),它们并非被设计用来“经由baseclass接口处置derived class对象”,因此它们不需要virtual析构函数。
请记住
- polymorphic(带多态性质的)base classes应该声明一个virtual析构函数。如果class带有任何 virtual函数,它就应该拥有一个virtual析构函数。
- Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性(polymorphically),就不该声明virtual析构函数
相关文章:

Effective C++条款07——为多态基类声明virtual析构函数(构造/析构/赋值运算)
有许多种做法可以记录时间,因此,设计一个TimeKeeper base class和一些derived classes 作为不同的计时方法,相当合情合理: class TimeKeeper { public:TimeKeeper();~TimeKeeper();// ... };class AtomicClock: public TimeKeepe…...

用友Java后端笔试2023-8-5
计算被直线划分区域 在笛卡尔坐标系,存在区域[A,B],被不同线划分成多块小的区域,简单起见,假设这些不同线都直线并且不存在三条直线相交于一点的情况。 img 那么,如何快速计算某个时刻,在 X 坐标轴上[ A,…...

idea2023 springboot2.7.5+mybatis+jsp 初学单表增删改查
创建项目 因为2.7.14使用量较少,特更改spring-boot为2.7.5版本 配置端口号 打开Sm01Application类,右键运行启动项目,或者按照如下箭头启动 启动后,控制台提示如下信息表示成功 此刻在浏览器中输入:http://lo…...

大语言模型之四-LlaMA-2从模型到应用
最近开源大语言模型LlaMA-2火出圈,从huggingface的Open LLM Leaderboard开源大语言模型排行榜可以看到LlaMA-2还是非常有潜力的开源商用大语言模型之一,相比InstructGPT,LlaMA-2在数据质量、培训技术、能力评估、安全评估和责任发布方面进行了…...

Android 远程真机调研
背景 现有的安卓测试机器较少,很难满足 SDK 的兼容性测试及线上问题(特殊机型)验证,基于真机成本较高且数量较多的前提下,可以考虑使用云测平台上的机器进行验证,因此需要针对各云测平台进行调研、比较。 …...

B. 攻防演练 (2021CCPC女生赛)
题意: 给出一个长度为n的字符,字符是前m个小写字母,有q个询问,每次询问一个最短子序列的长度满足不是[l,r]内任意一个子序列 思路: [l,r]中子序列可以看成是从[l,r]中的某个位置开始,跳到下一个字符的位…...

MAC环境,在IDEA执行报错java: -source 1.5 中不支持 diamond 运算符
Error:(41, 51) java: -source 1.5 中不支持 diamond 运算符 (请使用 -source 7 或更高版本以启用 diamond 运算符) 进入设置 修改java版本 pom文件中加入 <plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin&l…...

Tomcat日志中文乱码
修改安装目录下的日志配置 D:\ProgramFiles\apache-tomcat-9.0.78\conf\logging.properties java.util.logging.ConsoleHandler.encoding GBK...

最小生成树 — Prim算法
同Kruskal算法一样,Prim算法也是最小生成树的算法,但与Kruskal算法有较大的差别。 Prim算法整体是通过“解锁” “选中”的方式,点 -> 边 -> 点 -> 边。 因为是最小生成树,所以针对的也是无向图,所以可以随意…...

如何使用PHP Smarty模板进行AJAX交互?
首先,我们要明白,AJAX是一种在无需刷新整个页面的情况下,与服务器进行通信的技术。这对于改善用户体验来说,是个大宝贝。而PHP Smarty模板则是PHP的一种模板引擎,它使得设计和开发人员能够更好地分离逻辑和显示。 现在…...

nginx反向代理、负载均衡
修改nginx.conf的配置 upstream nginx_boot{# 30s内检查心跳发送两次包,未回复就代表该机器宕机,请求分发权重比为1:2server 192.168.87.143 weight100 max_fails2 fail_timeout30s; server 192.168.87.1 weight200 max_fails2 fail_timeout30s;# 这里的…...

React Native文本添加下划线
import { StyleSheet } from react-nativeconst styles StyleSheet.create({mExchangeCopyText: {fontWeight: bold, color: #1677ff, textDecorationLine: underline} })export default styles...

微服务-Nacos(配置管理)
配置更改热更新 在Nacos中添加配置信息: 在弹出表单中填写配置信息: 配置获取的步骤如下: 1.引入Nacos的配置管理客户端依赖(A、B服务): <!--nacos的配置管理依赖--><dependency><groupId&…...

UML图绘制 -- 类图
1.类图的画法 类 整体是个矩形,第一层类名,第二层属性,第三层方法。 :public- : private# : protected空格: 默认的default 对应的类写法。 public class Student {public String name;public Integer age;protected I…...

SAP ME2L/ME2M/ME3M报表增强添加字段(包含:LMEREPI02、SE18:ES_BADI_ME_REPORTING)
ME2L、ME2M、ME3M这三个报表的字段增强,核心点都在同一个结构里 SE11:MEREP_OUTTAB_PURCHDOC 在这里加字段,如果要加的字段是EKKO、EKPO里的数据,直接加进去,啥都不用做,就完成了 如果要加的字段不在EKKO和EKPO这两个…...

探讨uniapp的数据缓存问题
异步就是不管保没保存成功,程序都会继续往下执行。同步是等保存成功了,才会执行下面的代码。使用异步,性能会更好;而使用同步,数据会更安全。 1 uni.setStorage(OBJECT) 将数据存储在本地缓存中指定的 key 中&#x…...

服务的拆分
纵向拆分 是从业务维度进行拆分。标准是按照业务的关联程度来决定,关联比较密切的业务适合拆分为一个微服务,而功能相对比较独立的业务适合单独拆分为一个微服务。 以社交App为例,你可以认为首页信息流是一个服务,评论是一个服务…...

Uniapp Syntax Error: Error: Unbalanced delimiter found in string
报错 in ./src/pages/user/components/tasks.vue?vue&typescript&langjs&Syntax Error: Error: Unbalanced delimiter found in string...这边导致文件的原因:可能是条件编译语法不小心删了某个字符,导致不全,无法形成一对。 //…...

视频集中存储EasyCVR视频汇聚平台定制项目增加AI智能算法
安防视频集中存储EasyCVR视频汇聚平台,可支持海量视频的轻量化接入与汇聚管理。平台能提供视频存储磁盘阵列、视频监控直播、视频轮播、视频录像、云存储、回放与检索、智能告警、服务器集群、语音对讲、云台控制、电子地图、平台级联、H.265自动转码等功能。为了便…...

确保Django项目的稳定运行和持续改进
确保Django项目的稳定运行和持续改进 引言 Django是一个强大的Python Web框架,用于构建高效、可靠的Web应用程序。然而,部署一个Django项目并不意味着工作已经完成。在项目上线之后,确保项目的稳定运行并不断进行改进是非常重要的。本博客将…...

HAProxy负载均衡 代理
1.安装 yum -y install haproxy 2.配置文件 /etc/haproxy 下 global log 127.0.0.1 local2 #日志定义级别 chroot /var/lib/haproxy #当前工作目录 pidfile /var/run/haproxy.pid #进程id maxconn 4000 #最大连接…...

前端面试的游览器部分(8)每天10个小知识点
目录 系列文章目录前端面试的游览器部分(1)每天10个小知识点前端面试的游览器部分(2)每天10个小知识点前端面试的游览器部分(3)每天10个小知识点前端面试的游览器部分(4)每天10个小知…...

【【verilog典型电路设计之流水线结构】】
verilog典型电路设计之流水线结构 下图是一个4位的乘法器结构,用verilog HDL 设计一个两级流水线加法器树4位乘法器 对于流水线结构 其实需要做的是在每级之间增加一个暂存的数据用来存储 我们得到的东西 我们一般来说会通过在每一级之间插入D触发器来保证数据的联…...

大数据课程K2——Spark的RDD弹性分布式数据集
文章作者邮箱:yugongshiye@sina.cn 地址:广东惠州 ▲ 本章节目的 ⚪ 了解Spark的RDD结构; ⚪ 掌握Spark的RDD操作方法; ⚪ 掌握Spark的RDD常用变换方法、常用执行方法; 一、Spark最核心的数据结构——RDD弹性分布式数据集 1. 概述 初学Spark时,把RDD看…...

Seaborn数据可视化(一)
目录 1.seaborn简介 2.Seaborn绘图风格设置 21.参数说明: 2.2 示例: 1.seaborn简介 Seaborn是一个用于数据可视化的Python库,它是建立在Matplotlib之上的高级绘图库。Seaborn的目标是使绘图任务变得简单,同时产生美观且具有信…...

Sentinel规则持久化
首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。 示例代码: 1.编写处理类 //规则持久化 public class FilePersistence implements InitFunc {Value("spring.application:n…...

Transformer 相关模型的参数量计算
如何计算Transformer 相关模型的参数量呢? 先回忆一下Transformer模型论文《Attention is all your need》中的两个图。 设Transformer模型的层数为N,每个Transformer层主要由self-attention 和 Feed Forward组成。设self-attention模块的head个数为 …...

企业信息化过程----应用管理平台的构建过程
1.信息化的概念 信息化是一个过程,与工业化、现代化一样,是一个动态变化的过程。信息化已现代通信,网络、数据库技术为基础,将所有研究对象各个要素汇总至数据库,供特定人群生活、工作、学习、辅助决策等,…...

揭秘程序员的鄙视链,你在哪一层?看完我想哭
虽然不同的编程语言都有其优缺点,而且程序员之间的技能和能力更加重要,但是有些程序员可能会因为使用不同的编程语言而产生鄙视链。 以下是一些可能存在的不同编程语言程序员之间的鄙视链: 低级语言程序员鄙视高级语言程序员:使用…...

在docker下进行mysql的主从复制
搭建步骤 1、拉取镜像 docker pull mysql:latest2、查看镜像 docker images3、创建启动容器 Master docker run -p 3306:3306 --name mysql-master -e MYSQL_ROOT_PASSWORD123456 -d mysql:latestSlave docker run -p 3307:3306 --name mysql-slave -e MYSQL_ROOT_PASSWO…...