(delphi11最新学习资料) Object Pascal 学习笔记---第9章第5节(异常与构造函数)

9.5 异常与构造函数

​ 围绕异常还有一个稍微高级一点的问题,即当异常在对象的构造函数中产生时会发生什么情况。并非所有 Object Pascal 程序员都知道,在这种情况下,将调用对象的析构函数(如果有的话)。

​ 这一点很重要,因为它意味着一个部分初始化的对象可能会被调用析构函数。如果想当然地认为内部对象存在于析构函数中,因为它们是在构造函数中创建的,那么在出现实际错误时,可能会陷入一些危险的境地(即在第一个异常处理完毕之前引发另一个异常)。

​ 这也意味着,try-finally 的正确顺序应该是在代码块外创建对象,因为编译器会自动对其进行保护。因此,如果构造函数失败,就没有必要释放对象。这就是为什么 Object Pascal 的标准编码方式是通过写入以下内容来保护对象:

AnObject := AClass.Create;
try
  // 使用对象...
finally
  AnObject.Free;
end;

注解:类似的情况也发生在 TObject 类的两个特殊方法 AfterDestruction 和 BeforeConstruction 上,它们是为兼容 C++ 而引入的伪构造函数和伪析构函数(但在 Object Pascal 中很少使用)。请注意,如果 AfterConstruction 方法引发异常,就会调用 BeforeDestruction 方法(以及常规的析构函数)。

​ 鉴于我经常看到在析构函数中释放对象的错误,让我通过一个实际的演示来进一步说明这个问题以及实际的解决方法。假设你有一个包含字符串列表的类,你编写了以下代码来创建和销毁该类(ConstructorExcept 项目的一部分):

type
  TObjectWithList = class
  private
    FStringList: TStringList;
  public
    constructor Create(Value: Integer);
    destructor Destroy; override;
  end;

constructor TObjectWithList.Create(Value: Integer);
begin
  if Value < 0 then
    raise Exception.Create('Negative value not allowed');
  FStringList := TStringList.Create;
  FStringList.Add(Value.ToString);
end;

destructor TObjectWithList.Destroy;
begin
  FStringList.Clear;
  FStringList.Free;
  inherited;
end;

​ 乍一看,代码似乎是正确的。构造函数分配子对象,而析构函数恰当地释放子对象。此外,调用代码的编写方式是,如果在构造函数之后出现异常,则调用 Free 方法,但如果异常出现在构造函数中,则什么也不会发生:

var
  Obj: TObjectWithList;
begin
  Obj := TObjectWithList.Create(-10);
  try
    // 进行一些操作
  finally
    Show('Freeing object');
    Obj.Free;
  end;
end;

​ 这样行得通吗?绝对不行!当运行这段代码时,异常会在构造函数中出现,发生在创建字符串列表之前,系统会立即调用析构函数,试图清除不存在的列表,从而引发访问违规或类似错误。

​ 为什么会出现这种情况呢?同样,如果在构造函数中颠倒顺序(先创建字符串列表,后引发异常),一切都能正常工作,因为析构函数确实需要释放字符串列表。但这并不是真正的解决办法,只是一种变通方法。你始终应该考虑的是保护析构函数的代码,使其永远不会假定构造函数已被完全执行。下面就是一个例子:

destructor TObjectWithList.Destroy;
begin
  if Assigned(FStringList) then
  begin
    FStringList.Clear;
    FreeAndNil(FStringList);
  end;
  inherited;
end;

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C语言中局部变量和全局变量是否可以重名?为什么?

可以重名 在C语言中, 局部变量指的是定义在函数内的变量, 全局变量指的是定义在函数外的变量 他们在程序中的使用方法是不同的, 当重名时, 局部变量在其所在的作用域内具有更高的优先级, 会覆盖或者说隐藏同名的全局变量 具体来说: 局部变量的生命周期只在函数内部,如果出了…

专业140+总分410+北京理工大学826信号处理导论考研经验北理工电子信息通信工程,真题,参考书,大纲。

今年考研专业课826信号处理导论&#xff08;信号系统和数字信号处理&#xff09;140&#xff0c;总分410&#xff0c;顺利上岸&#xff01;回看去年将近一年的复习&#xff0c;还是记忆犹新&#xff0c;有不少经历想和大家分享&#xff0c;有得有失&#xff0c;希望可以对大家复…

[管理者与领导者-163] :团队管理 - 高效执行力 -1- 高效沟通的架构、关键问题、注意事项

目录 前言&#xff1a;沟通是管理者实施管理最重要的工作 一、人与人沟通模型 1.1 模型 1.2 完整过程 1.3 发送和接受方式 1.4 传输 1.5 关于编码与解码 1.6 反馈 1.7 沟通中常见问题 二、管理者如何提高沟通的效率 2.1 为什么管理者布置任务后&#xff0c;总有人…

HarmonyOS实战开发-状态管理、通过使用页面级的状态变量 和应用级的状态变量 来实现应用的状态管理。

介绍 本示例通过使用页面级的状态变量 和应用级的状态变量 来实现应用的状态管理。 效果预览 使用说明 1.点击首页中的基本类型进入对应页面&#xff0c;点击按钮可以更改圆形的颜色&#xff1b;点击查看源码可以展示基本类型功能效果的源码。 2.点击首页中的数组类型进入对…

微信小程序实现预约生成二维码

业务需求&#xff1a;点击预约按钮即可生成二维码凭码入校参观~ 一.创建页面 如下是博主自己写的wxml&#xff1a; <swiper indicator-dots indicator-color"white" indicator-active-color"blue" autoplay interval"2000" circular > &…

为什么光伏探勘测绘需要无人机?

随着全球对可再生能源需求的不断增长&#xff0c;光伏产业也迎来了快速发展的机遇。光伏电站作为太阳能发电的主要形式之一&#xff0c;其建设前期的探勘测绘工作至关重要。在这一过程中&#xff0c;无人机技术的应用正逐渐展现出其独特的优势。那么&#xff0c;为什么光伏探勘…

【数据结构】4.List的介绍

目录 1.什么是List 2.常见接口介绍 3.List的使用 1.什么是List 在集合框架中&#xff0c;List是一个接口&#xff0c;继承自Collection。 Collection也是一个接口&#xff0c;该接口中规范了后序容器中常用的一些方法&#xff0c;具体如下&#xff1a; Iterable也是一个接口…

HashMap扩容原理(带源码分析)

HashMap的扩容原理 1.扩容流程图 注&#xff1a;拆分链表的规则 这里拆分链表时的一个比较&#xff1a;e.hash & oldCap 0 意思是&#xff1a;某一个节点的hash值和老数组容量求&运算。如果等于0&#xff0c;当前元素在老数组中的位置就是在新数组中的位置。如果不等…

使用新一代一站式 AI Bot 开发平台扣子coze,搭建我的第一个AI Bot(前端魔法师) ,

目录 1.概述​ 2.功能与优势 3.使用扣子 4.人设与回复逻辑 5.添加插件 6.预览与调试 7.发布bot Store 8.环境大家体验&#xff08;给大家内置了比较屌的插件&#xff09; 9.推荐阅读&#xff1a; 1.概述​ 扣子是新一代一站式 AI Bot 开发平台。无论你是否有编程基础…

面试经典算法系列之二叉树7 -- 二叉树的中序遍历

面试经典算法22 - 二叉树的中序遍历 LeetCode.94 公众号&#xff1a;阿Q技术站 问题描述 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,3,2]示例 2&#xff1a; 输入&…

【鸿蒙开发】第二十一章 Media媒体服务(二)--- 音频播放和录制

1 AVPlayer音频播放 使用AVPlayer可以实现端到端播放原始媒体资源&#xff0c;本开发指导将以完整地播放一首音乐作为示例&#xff0c;向开发者讲解AVPlayer音频播放相关功能。 以下指导仅介绍如何实现媒体资源播放&#xff0c;如果要实现后台播放或熄屏播放&#xff0c;需要…

稀碎从零算法笔记Day48-LeetCode:三角形最小路径和

题型&#xff1a;DP、二维DP、矩阵 链接&#xff1a;120. 三角形最小路径和 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一个三角形 triangle &#xff0c;找出自顶向下的最小路径和。 每一步只能移动到下一行中相邻的结点上。相邻的…

Project Euler_Problem 193_Few Repeated Digits_欧拉筛+容斥公式

解题思路&#xff1a;暴力搜索 代码&#xff1a; void solve() {ll i, j,k,x,y,z,p,q,u,v,l,l1;N 999966663333, NN 1024;//N 1000;double a, b, c,d;M.NT.get_prime_Euler(1000000);l M.NT.pcnt;for (i 1; i < l; i) {u M.NT.prime[i];v M.NT.prime[i 1];x u * …

交叉熵损失函数介绍

交叉熵是信息论中的一个重要概念&#xff0c;它的大小表示两个概率分布之间的差异&#xff0c;可以通过最小化交叉熵来得到目标概率分布的近似分布。 为了理解交叉熵&#xff0c;首先要了解下面这几个概念。 自信息 信息论的基本想法是&#xff0c;一个不太可能的事件发生了…

蓝桥杯:握手问题和小球反弹问题

试题 A: 握手问题 本题总分&#xff1a; 5 分 【问题描述】 小蓝组织了一场算法交流会议&#xff0c;总共有 50 人参加了本次会议。在会议上&#xff0c; 大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手&#xff08;且仅有一次&#x…

FRR-NET:用于弱光图像增强的快速重参数残差网络

很久之前写的文章&#xff0c;前两天才见刊。项目的具体代码因项目原因无法公布&#xff0c;我自己重新训练了一个版本&#xff08;包含两类预训练模型&#xff09;&#xff0c;供初学者参考。本文主要为AB式创新。 文章链接&#xff1a;paper 代码链接&#xff1a;GitHub || …

【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控件位置

往期回顾 【QT入门】 Qt自定义控件与样式设计之QSlider用法及qss-CSDN博客 【QT入门】Qt自定义控件与样式设计之qss的加载方式-CSDN博客 【QT入门】Qt自定义控件与样式设计之控件提升与自定义控件-CSDN博客 【QT入门】Qt自定义控件与样式设计之鼠标相对、绝对位置、窗口位置、控…

【Unity】Feature has expired(H0041)

【背景】 在一台很久不用的电脑上更新了个人License&#xff0c;并导入了云项目&#xff0c;打开时却报错&#xff1a; 【分析】 网上查说要删缓存等等&#xff0c;试过都不行。重装Hub也不行。 这种环境类型的原因很难从信息入手定位错误。 所以我自己检查项目上有什么问题…

温故知新之-TCP Keepalive机制及长短连接

[学习记录] 前言 TCP连接一旦建立&#xff0c;只要连接双方不主动 close &#xff0c;连接就会一直保持。但建立连接的双方并不是一直都存在数据交互&#xff0c;所以在实际使用中会存在两种情况&#xff1a;一种是每次使用完&#xff0c;主动close&#xff0c;即短连接&…

ChatGPT 和 Elasticsearch:使用 Elastic 数据创建自定义 GPT

作者&#xff1a;Sandra Gonzales ChatGPT Plus 订阅者现在有机会创建他们自己的定制版 ChatGPT&#xff0c;称为 GPT&#xff0c;这替代了之前博客文章中讨论的插件。基于本系列的第一部分的基础 —— 我们深入探讨了在 Elastic Cloud 中设置 Elasticsearch 数据和创建向量嵌…