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

本文主要是介绍(delphi11最新学习资料) Object Pascal 学习笔记---第9章第5节(异常与构造函数),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

9.5 异常与构造函数

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

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

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

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

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

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

typeTObjectWithList = classprivateFStringList: TStringList;publicconstructor Create(Value: Integer);destructor Destroy; override;end;constructor TObjectWithList.Create(Value: Integer);
beginif Value < 0 thenraise Exception.Create('Negative value not allowed');FStringList := TStringList.Create;FStringList.Add(Value.ToString);
end;destructor TObjectWithList.Destroy;
beginFStringList.Clear;FStringList.Free;inherited;
end;

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

varObj: TObjectWithList;
beginObj := TObjectWithList.Create(-10);try// 进行一些操作finallyShow('Freeing object');Obj.Free;end;
end;

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

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

destructor TObjectWithList.Destroy;
beginif Assigned(FStringList) thenbeginFStringList.Clear;FreeAndNil(FStringList);end;inherited;
end;

这篇关于(delphi11最新学习资料) Object Pascal 学习笔记---第9章第5节(异常与构造函数)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/905498

相关文章

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

Java捕获ThreadPoolExecutor内部线程异常的四种方法

《Java捕获ThreadPoolExecutor内部线程异常的四种方法》这篇文章主要为大家详细介绍了Java捕获ThreadPoolExecutor内部线程异常的四种方法,文中的示例代码讲解详细,感... 目录方案 1方案 2方案 3方案 4结论方案 1使用 execute + try-catch 记录

Mysql中InnoDB与MyISAM索引差异详解(最新整理)

《Mysql中InnoDB与MyISAM索引差异详解(最新整理)》InnoDB和MyISAM在索引实现和特性上有差异,包括聚集索引、非聚集索引、事务支持、并发控制、覆盖索引、主键约束、外键支持和物理存... 目录1. 索引类型与数据存储方式InnoDBMyISAM2. 事务与并发控制InnoDBMyISAM

Redis 内存淘汰策略深度解析(最新推荐)

《Redis内存淘汰策略深度解析(最新推荐)》本文详细探讨了Redis的内存淘汰策略、实现原理、适用场景及最佳实践,介绍了八种内存淘汰策略,包括noeviction、LRU、LFU、TTL、Rand... 目录一、 内存淘汰策略概述二、内存淘汰策略详解2.1 ​noeviction(不淘汰)​2.2 ​LR

StarRocks索引详解(最新整理)

《StarRocks索引详解(最新整理)》StarRocks支持多种索引类型,包括主键索引、前缀索引、Bitmap索引和Bloomfilter索引,这些索引类型适用于不同场景,如唯一性约束、减少索引空... 目录1. 主键索引(Primary Key Index)2. 前缀索引(Prefix Index /

解决java.lang.NullPointerException问题(空指针异常)

《解决java.lang.NullPointerException问题(空指针异常)》本文详细介绍了Java中的NullPointerException异常及其常见原因,包括对象引用为null、数组元... 目录Java.lang.NullPointerException(空指针异常)NullPointer

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

Java中实现订单超时自动取消功能(最新推荐)

《Java中实现订单超时自动取消功能(最新推荐)》本文介绍了Java中实现订单超时自动取消功能的几种方法,包括定时任务、JDK延迟队列、Redis过期监听、Redisson分布式延迟队列、Rocket... 目录1、定时任务2、JDK延迟队列 DelayQueue(1)定义实现Delayed接口的实体类 (

SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程

《SpringBoot中整合RabbitMQ(测试+部署上线最新完整)的过程》本文详细介绍了如何在虚拟机和宝塔面板中安装RabbitMQ,并使用Java代码实现消息的发送和接收,通过异步通讯,可以优化... 目录一、RabbitMQ安装二、启动RabbitMQ三、javascript编写Java代码1、引入

shell脚本自动删除30天以前的文件(最新推荐)

《shell脚本自动删除30天以前的文件(最新推荐)》该文章介绍了如何使用Shell脚本自动删除指定目录下30天以前的文件,并通过crontab设置定时任务,此外,还提供了如何使用Shell脚本删除E... 目录shell脚本自动删除30天以前的文件linux按照日期定时删除elasticsearch索引s