Delphi FreeAndNil:寻找替代实现

2023-12-13

注意:请耐心听我说,我感觉有点「火焰烤」由于一些讨论here and here以及我报告的一些问题here and here.

一些背景

旧的(10.4 之前)FreeAndNil看起来像这样:

FreeAndNil(var SomeObject)

新的和新鲜的FreeAndNil看起来像这样:

FreeAndNil(const [ref] SomeObject: TObject);

IMO 都有各自的缺点:

  • 旧的不做任何类型检查,所以调用FreeAndNil在指针、记录和接口上编译得很好,但在运行时会产生有趣但通常不需要的效果。 (完全疯狂,或者如果你幸运的话,它会因 EAccessViolation、EInvalidOperation 等而停止。)
  • 新的接受一个 const 参数,因此也接受任何对象。但随后提供的对象指针实际上是使用一些更改的古怪的代码.
  • 您现在可以调用新的FreeAndNil像这样:FreeAndNil(TObject.Create)它会编译甚至运行得很好。我喜欢旧的FreeAndNil当我出错时它会警告我并提供例如属性而不是字段。不确定如果您为此提供对象类型属性会发生什么FreeAndNil执行。没有尝试。

如果我们将签名更改为FreeAndNil(var SomeObject:TObject)那么它将不允许我们传递任何其他变量类型TObject类型。这也有道理,好像没有一样FreeAndNil,可以轻松更改作为类型提供的变量TComponent在例程中将 var 变量更改为完全不同类型的对象,例如TCollection。当然FreeAndNil不会做这样的事情,因为它总是将 var 参数更改为 nil。

所以这使得FreeAndNil一个特殊情况。甚至可能特别到足以说服delphi添加一个编译器魔法 FreeAndNil执行?有人投票吗?

潜在的解决方法

我想出了下面的代码作为替代方法(这里作为辅助方法,但也可以是TObject实现),它结合了两个世界。这Assert将有助于在运行时查找无效调用。

procedure TSGObjectHelper.FreeAndNilObj(var aObject);
begin
  if Assigned(self) then
  begin
    Assert(TObject(aObject)=self,ClassName+'.FreeAndNil Wrong parameter provided!');
    pointer(aObject):=nil;
    Destroy;
  end;
end;

用法会是这样的:

var MyObj:=TSOmeObject.Create;
...
MyObj.FreeAndNilObj(MyObj);

我实际测试过这个例程,它甚至比 10.4 还要快一些FreeAndNil执行。我想是因为我先做作业检查然后打电话Destroy直接地。 我做什么not非常喜欢的是:

  • 类型检查在运行时进行,并且仅在断言为 ON 时进行。
  • 感觉就像必须传递同一个变量两次。这不一定是真的/必需的。它必须是同一个对象,并且参数必须是变量。

另一项调查

但如果可以不带参数调用该多好

var MyObj:=TSomeObject.Create;
...
MyObj.FreeAndNil;

所以我乱搞了self指针并设法将其设置为nil使用 10.4 中使用的相同 Hacky-Wacky 代码FreeAndNil。嗯...这有效inside方法,self指向nil。但打电话之后FreeAndNil像这样,MyObj 变量不是 nil,而是一个过时的指针。 (这正是我所期望的。)此外,MyObj可以是属性或例程(的结果)、构造函数等。

so nope这里也...

最后的问题是:

您能想到一个更干净/更好的解决方案或技巧吗:

  • FreeAndNil(var aObject:TObject) 具有不太严格的类型检查编译时(可能是编译器指令?),因此它允许编译和调用变量any对象类型。
  • 当某些东西通过时抱怨编译时间not某种对象类型的变量/字段
  • 帮助描述什么是最好的解决方案/要求RSP-29716

唯一正确的解决办法FreeAndNil这既是类型安全的,又不允许释放函数结果,并且属性将是通用 var 参数:

 procedure FreeAndNil<T: class>(var Obj: T); inline;

但是,目前 Delphi 编译器不允许在独立过程和函数上使用泛型https://quality.embarcadero.com/browse/RSP-13724

尽管如此,这并不意味着你不能拥有通用的FreeAndNil实现,只是它会比必要的更冗长一些。

type
  TObj = class
  public
    class procedure FreeAndNil<T: class>(var Obj: T); static; inline;
  end;

class procedure TObj.FreeAndNil<T>(var Obj: T);
var
  Temp: TObject;
begin
  Temp := Obj;
  Obj := nil;
  Temp.Free;
end;

Rio 中引入的类型推断将允许您在不指定通用签名的情况下调用它:

TObj.FreeAndNil(Obj);

调用(和使用)泛型FreeAndNil在较旧的 Delphi 版本中也是可能的,但更加冗长

TObj.FreeAndNil<TFoo>(Obj);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Delphi FreeAndNil:寻找替代实现 的相关文章

随机推荐

  • 运行 git init 两次是否会初始化存储库或重新初始化现有存储库?

    当您发出命令时 现有的 git 存储库会发生什么git init again 我创建了一个存储库git init 创建文件 添加 提交 检查状态 没有要提交的内容 然后创建另一个文件 检查状态 我可以看到它没有按预期被跟踪 然后 错误地说
  • 为什么当我创建新存储库时 github 显示灰色文件夹?

    git命令 git init git add git commit m project git remote add origin https github com git push u origin master 灰色文件夹 github
  • MySql 使用哪种数据结构? [关闭]

    很难说出这里问的是什么 这个问题模棱两可 含糊不清 不完整 过于宽泛或言辞激烈 无法以目前的形式合理回答 如需帮助澄清此问题以便重新打开 访问帮助中心 MySql 使用哪种数据结构 可能很多 但从 B 树开始
  • 页面刷新后如何保留div内容

    我正在使用 Jquery 创建一个动态 div 并且尝试缓存它 以便在页面刷新后将其取回 请帮助了解如何实现这一点 粘贴下面的代码
  • 增加PHP中的max_execution_time?

    我正在尝试将大文件上传到我的服务器 我的服务器支持post max size192mb 和max execution time600 秒 当我上传 100mb 文件时 执行将在 600 秒后停止 因此文件不会上传到服务器 我怎样才能增加ma
  • 如何获取 geom_segment 显示图例

    我有下面的图 有 2 段 如何为线段添加图例 理想情况下 最终结果有 2 个图例 其中之一就是当前的 点图例 另一个图例是单个图例 带有红色虚线标记为 段图例 这是代码 set seed 11 x rnorm 100 y rnorm 100
  • 如何有效地知道字符中第一个(左 -> 右)“1”位的位置[重复]

    这个问题在这里已经有答案了 正如标题所说 我有一个字符 例如00101011 我如何知道其中第一个 1 位的位置 在本例中 它是 6 如果我们认为最右边的位置是 0 则它是 5 我知道 for 循环移位会有所帮助 但是有更有效的方法吗 有一
  • 替换字符串中的变量占位符

    我的字符串看起来像这样 您可以使用促销直到 开始日期 30 我需要更换 Start Date 30 带有实际日期的占位符 即销售的开始日期加上 30 天 或任何其他数字 Start Date 也可能单独出现而不添加编号 此外 占位符内的任何
  • SASS 变量和继承

    假设我有两个几乎相同的 HTML 结构 但具有不同的class名称 它们仅存在几个变量不同 例如width and height 通过使用 SASS SCSS 变量 我想我可以做这样的事情 widget a width 50px widge
  • iOS 6 Facebook 登录不刷新访问令牌

    我正在阅读的任何内容 许多 FB 开发文章和 SO 问题 都没有帮助 所以我想我应该在这里发帖 我正在尝试让这一切与 iOS 6 和 Facebook SDK 3 1 1 一起使用 我有一个非常基本的设置 我的 iOS 应用程序通过 Fac
  • 请帮我找出这个网络代理代码有什么问题

    我想编写一个网络代理来练习 这是我到目前为止的代码 returns a map that contains the port and the host def parseHostAndPort String data def objMap
  • 加快 Gatsby 性能

    我在工作中接到了一项提高项目绩效的任务 目前 Google Lighthouse 分数有所波动 但总体而言 分数并不是那么好 因此我们正在尝试找出如何提高其性能 以便能够向我们的领导者炫耀 我们的项目将整个 Gatsby 站点作为单个 Ja
  • PHP 中如何将十六进制转换为二进制?

    我正在尝试发送0x01十六进制作为字节使用socket write socket XXXX 1 功能 有部分文档 如果是 服务器将回复模块 0x01 如果不是 重播 0x00 服务器必须发送答案 1 字节十六进制格式 有多种选择 当使用pa
  • 画布动画中的闪烁图像

    window requestAnimFrame function callback return window requestAnimationFrame window webkitRequestAnimationFrame window
  • 在ipython中调用pylab.savefig而不显示

    我需要在文件中创建一个图形 而不在 IPython 笔记本中显示它 我不清楚之间的相互作用IPython and matplotlib pylab在这方面 但是 当我打电话时pylab savefig test png 除了保存在中之外 还
  • K&R fopen 和 fillbuf 中的 C 段错误

    我对C很陌生 我在学习K R最后一章时遇到了一个问题 我正在尝试实施fopen and fillbuf 通过使用系统调用来实现功能 open and read 我完全复制了书中的源代码 但编译后反复出现分段错误 fp gt fd fd fp
  • 如何保证三个DIV无论内容如何高度相同

    div class section group div class col span 1 of 3 articleTeaserBoxColor div class test2n div class imgHolder img class i
  • 遍历所有表单元素,无论其类型如何

    我正忙于为我们的一位客户提供表单管理器 总体想法是为各个部门构建表单 我想创建一个微型系统来处理表单的验证等 而无需重做太多工作 尽可能自动化 我的第一个主要任务是 我想单击提交按钮 迭代整个表单 并根据特定的凭据和验证规则验证表单 然后再
  • ?:??运算符代替 IF|ELSE

    public string Source get if Source null return string Empty else return Source return Source string Empty set if Source
  • Delphi FreeAndNil:寻找替代实现

    注意 请耐心听我说 我感觉有点 火焰烤 由于一些讨论here and here以及我报告的一些问题here and here 一些背景 旧的 10 4 之前 FreeAndNil看起来像这样 FreeAndNil var SomeObjec