对于类运算符,是否允许对其自身进行隐式类型转换?

2024-02-28

我有一个记录,看起来像:

TBigint = record
    PtrDigits: Pointer;                  <-- The data is somewhere else.
    Size: Byte;
    MSB: Byte;
    Sign: Shortint;
    ...
    class operator Implicit(a: TBigint): TBigint;  <<-- is this allowed?
    ....

该代码是类前运算符遗留代码,但我想添加运算符。

我知道数据确实应该存储在动态字节数组中,但我不想更改代码,因为所有内容都在 x86 汇编中。

我想按照以下代码来触发底部的类运算符:

procedure test(a: TBignum);
var b: TBignum;
begin
  b:= a;  <<-- naive copy will tangle up the `PtrDigit` pointers.
  ....

如果我将隐式类型转换添加到自身,下面的代码会被执行吗?

class operator TBigint.Implicit(a: TBigint): TBigint;
begin
  sdpBigint.CreateBigint(Result, a.Size);
  sdpBigint.CopyBigint(a, Result);
end;

(如果它按我的预期工作,将测试并添加答案)。


My 第一个答案 https://stackoverflow.com/a/18810862/224704试图阻止重写赋值运算符的想法。我仍然坚持这个答案,因为遇到的许多问题都可以通过对象更好地解决。

然而,大卫非常正确地指出:TBigInt被实现为记录以利用运算符重载。 IE。a := b + c;。这是坚持基于记录的实施的一个很好的理由。

因此,我提出了一种一石二鸟的替代解决方案:

  • 它消除了我在其他答案中解释的内存管理风险。
  • 并提供了一种简单的机制来实现 Copy-on-Write 语义。

(我仍然建议,除非有充分的理由保留基于记录的解决方案,否则请考虑切换到基于对象的解决方案。)

总体思路如下:

  • 定义一个接口来表示 BigInt 数据。 (这最初可以是极简的,并且仅支持指针的控制 - 正如我的示例中一样。这将使现有代码的初始转换变得更容易。)
  • 定义上述接口的实现,该接口将由TBigInt record.
  • 接口解决了第一个问题,因为接口是托管类型;当记录超出范围时,Delphi 将取消引用该接口。因此,当不再需要时,底层对象将自行销毁。
  • 该接口还提供了解决第二个问题的机会,因为我们可以检查RefCount了解我们是否应该进行写入时复制。
  • 请注意,从长远来看,将某些 BigInt 实现从记录移至类和接口可能是有益的。

以下代码是精简的“big int”实现,纯粹是为了说明概念。 (即“大”整数仅限于常规 32 位数字,并且仅实现了加法。)

type
  IBigInt = interface
    ['{1628BA6F-FA21-41B5-81C7-71C336B80A6B}']
    function GetData: Pointer;
    function GetSize: Integer;
    procedure Realloc(ASize: Integer);
    function RefCount: Integer;
  end;

type
  TBigIntImpl = class(TInterfacedObject, IBigInt)
  private
    FData: Pointer;
    FSize: Integer;
  protected
    {IBigInt}
    function GetData: Pointer;
    function GetSize: Integer;
    procedure Realloc(ASize: Integer);
    function RefCount: Integer;
  public
    constructor CreateCopy(ASource: IBigInt);
    destructor Destroy; override;
  end;

type
  TBigInt = record
    PtrDigits: IBigInt;
    constructor CreateFromInt(AValue: Integer);
    class operator Implicit(AValue: TBigInt): Integer;
    class operator Add(AValue1, AValue2: TBigInt): TBigInt;
    procedure Add(AValue: Integer);
  strict private
    procedure CopyOnWriteSharedData;
  end;

{ TBigIntImpl }

constructor TBigIntImpl.CreateCopy(ASource: IBigInt);
begin
  Realloc(ASource.GetSize);
  Move(ASource.GetData^, FData^, FSize);
end;

destructor TBigIntImpl.Destroy;
begin
  FreeMem(FData);
  inherited;
end;

function TBigIntImpl.GetData: Pointer;
begin
  Result := FData;
end;

function TBigIntImpl.GetSize: Integer;
begin
  Result := FSize;
end;

procedure TBigIntImpl.Realloc(ASize: Integer);
begin
  ReallocMem(FData, ASize);
  FSize := ASize;
end;

function TBigIntImpl.RefCount: Integer;
begin
  Result := FRefCount;
end;

{ TBigInt }

class operator TBigInt.Add(AValue1, AValue2: TBigInt): TBigInt;
var
  LSum: Integer;
begin
  LSum := Integer(AValue1) + Integer(AValue2);
  Result.CreateFromInt(LSum);
end;

procedure TBigInt.Add(AValue: Integer);
begin
  CopyOnWriteSharedData;

  PInteger(PtrDigits.GetData)^ := PInteger(PtrDigits.GetData)^ + AValue;
end;

procedure TBigInt.CopyOnWriteSharedData;
begin
  if PtrDigits.RefCount > 1 then
  begin
    PtrDigits := TBigIntImpl.CreateCopy(PtrDigits);
  end;
end;

constructor TBigInt.CreateFromInt(AValue: Integer);
begin
  PtrDigits := TBigIntImpl.Create;
  PtrDigits.Realloc(SizeOf(Integer));
  PInteger(PtrDigits.GetData)^ := AValue;
end;

class operator TBigInt.Implicit(AValue: TBigInt): Integer;
begin
  Result := PInteger(AValue.PtrDigits.GetData)^;
end;

在我构建建议的解决方案时编写了以下测试。他们证明:一些基本功能,写时复制按预期工作,并且不存在内存泄漏。

procedure TTestCopyOnWrite.TestCreateFromInt;
var
  LBigInt: TBigInt;
begin
  LBigInt.CreateFromInt(123);
  CheckEquals(123, LBigInt);
  //Dispose(PInteger(LBigInt.PtrDigits)); //I only needed this until I 
                                          //started using the interface
end;

procedure TTestCopyOnWrite.TestAssignment;
var
  LValue1: TBigInt;
  LValue2: TBigInt;
begin
  LValue1.CreateFromInt(123);
  LValue2 := LValue1;
  CheckEquals(123, LValue2);
end;

procedure TTestCopyOnWrite.TestAddMethod;
var
  LValue1: TBigInt;
begin
  LValue1.CreateFromInt(123);
  LValue1.Add(111);

  CheckEquals(234, LValue1);
end;

procedure TTestCopyOnWrite.TestOperatorAdd;
var
  LValue1: TBigInt;
  LValue2: TBigInt;
  LActualResult: TBigInt;
begin
  LValue1.CreateFromInt(123);
  LValue2.CreateFromInt(111);

  LActualResult := LValue1 + LValue2;

  CheckEquals(234, LActualResult);
end;

procedure TTestCopyOnWrite.TestCopyOnWrite;
var
  LValue1: TBigInt;
  LValue2: TBigInt;
begin
  LValue1.CreateFromInt(123);
  LValue2 := LValue1;

  LValue1.Add(111); { If CopyOnWrite, then LValue2 should not change }

  CheckEquals(234, LValue1);
  CheckEquals(123, LValue2);
end;

Edit

添加了演示使用的测试TBigInt作为过程的值参数。

procedure TTestCopyOnWrite.TestValueParameter;
  procedure CheckValueParameter(ABigInt: TBigInt);
  begin
    CheckEquals(2, ABigInt.PtrDigits.RefCount);
    CheckEquals(123, ABigInt);
    ABigInt.Add(111);
    CheckEquals(234, ABigInt);
    CheckEquals(1, ABigInt.PtrDigits.RefCount);
  end;
var
  LValue: TBigInt;
begin
  LValue.CreateFromInt(123);
  CheckValueParameter(LValue);
end;
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对于类运算符,是否允许对其自身进行隐式类型转换? 的相关文章

  • 在 Delphi 中,我的 DLL 中是否必须分配函数的返回 pchar

    我有一个 DLL 其中有一个返回 pchar 的函数 以避免必须使用 borlndmm 我最初所做的是将字符串转换为 pchar 并返回 Result pChar SomeFuncThatReturnsString 但 90 的情况下我都能
  • 如何解决内存分段并强制FastMM释放内存给OS?

    注意 32 位应用程序不计划迁移到 64 位 我正在使用一个非常消耗内存的应用程序 并且几乎优化了与内存分配 取消分配相关的所有相关路径 应用程序本身没有内存泄漏 没有句柄泄漏 没有任何其他类型的泄漏 据我所知并经过测试 我无法触及的第 3
  • 为什么我不能在接收数组参数的函数中使用 SetLength?

    我正在尝试使用以下函数来设置动态数组 即 var 参数 的长度 当我尝试编译代码时只有一个错误 dcc64 错误 lolcode dpr 138 E2008 不兼容类型 function execute var command array
  • 如何更改 Delphi 2010 IDE 中编辑器选项卡的字体大小?

    有谁知道如何更改 Delphi 2010 IDE 中编辑器选项卡的字体大小 我的 1080p 22 显示器的字体太小 无法阅读 而且会导致眼睛疼痛 一些笔记 它不尊重系统的 DPI 设置 因此更改系统设置没有帮助 而且 我现在已经使用 14
  • delphi定时器比定时器服务中断例程更快

    大家好 我被要求为某人维护一个基于 Delphi 5 的程序 该程序使用一个计时器对象每 50 毫秒计时一次 并且在每次计时结束时运行单线程代码块 我只是想知道 如果执行这段代码所花费的时间比计时器滴答间隔长 会发生什么 这会很糟糕吗 例如
  • 如何正确重载流运算符以在多态类中进行打印?

    编辑 代码有一个拼写错误 现在它可以编译 但我仍然没有得到我想要的输出 我正在尝试重载流运算符std cout std fstream等等 但我无法正确处理多态性 我无法获得我想要看到的输出 我希望子类先显示超类的内容 然后显示其内容 而超
  • Delphi (Indy) TIdTCPClient 在线程中

    在互联网上 我看到通常将 TIdTCPClient 放置在自定义 TThread 后代中 为什么要这样做 有时我也在这样的线程中看到服务器 为什么 干杯 阿德里安 Indy 使用阻塞 I O 最好在线程中处理 这是 Indy 整体设计的核心
  • 在运行时创建 TQReport 元素

    在运行时创建 TQReport 元素 嗯 至少尝试一下 我不知道这份报告中应出现哪些标题或数据 我得到一个代表数据行和列的 TString 的 TList 我在组的带打印事件中植入 创建 指令 并在主数据行带的 OnNeedData 事件中
  • 为什么默认的三路运算符(spaceship <=>)生成相等运算符(==)而用户定义的三路运算符则不会? [复制]

    这个问题在这里已经有答案了 考虑这段代码 include
  • 如何以编程方式安排任务

    如何使用 delphi 7 像 Google updater 一样安排任务 我没有使用注册表 因为它被卡巴斯基防病毒软件检测为误报 我在注册表中作为启动项添加的任何内容都会被检测为特洛伊木马 因此我决定使用任务计划 下面的代码展示了如何删除
  • VCL.位图到 FMX.位图

    我在网上找到了这段代码 但 FMX Bitmap 没有扫描线 是否可以以某种方式将 VCL TBitmap 复制或绘制到 FMX Bitmap IFDEF MSWINDOWS type TBitmap FMX Types TBitmap T
  • 如何在Delphi XE中通过名称获取类类型引用?

    我实际上正在尝试使用 Rtti 来实现通用方法调用程序 它应该像这样工作 我将提供类名 方法名和参数 调用者将通过调用此类的指定方法来完成其工作 因此 我需要类引用才能获取其 Rtti 信息并寻找我想要调用的方法 有没有办法在不实现我想要使
  • 获取 TransactSql 批处理中的语句数计数

    对于不使用 Delphi 的读者 虽然以下内容是根据 Delphi 编码来表达的 但我的实际技术问题不是特定于 Delphi 的 而是关于如何找出 Sql Server 如何 理解 TransactSql 批处理提交给它 TAdoQuery
  • 如何仅在调试模式下激活 ReportMemoryLeaksOnShutdown?

    我需要激活ReportMemoryLeaksOnShutdown报告应用程序内存泄漏的功能 但仅限于调试模式 当 Delphi IDE 运行时 我怎样才能做到这一点 如果您的意思是使用调试构建配置 D2007 编译的 调试模式 则您将定义
  • Delphi TImageList 位图更改

    我正在使用 Delphi XE2 Update 3 Update 4 与我们的一些第 3 方组件不兼容 因此我们尚未更新 我在我的应用程序中使用 TImageList 我注意到很多时候当它从源视图切换到表单视图 F12 时 突然之前未修改的
  • 在运行时按需更改组件类

    我的问题与这里的想法类似 替换delphi中的组件类 https stackoverflow com q 4685863 937125 但我需要改变一个specific按需组件类 这是一些伪演示代码 unit Unit1 TForm1 cl
  • 如何遍历任意给定集合中的枚举?

    我有很多枚举类型 它们与相应的集合相结合 例如 type TMyEnum meOne meTwo meThree TMyEnums set of TMyEnum 我正在尝试提出一组可以运行的函数any枚举集 而不是为每个枚举编写单独的函数
  • TOpenDialog/NSOpenPanel 无法在沙盒 Delphi 应用程序中工作

    Firemonkey 应用程序中的 TOpenDialog 似乎存在问题 该应用程序已针对 Mac Appstore 进行沙箱处理 我使用XE3 但它也存在于XE2中 我其实在这里找到了一份QC报告 但仍然没有解决 http qc emba
  • 具有 csOwnerDrawFixed 样式的组合框如何表现得像 csDropDown 样式?

    我正在使用一个组合框 http docwiki embarcadero com Libraries en Vcl StdCtrls TComboBoxstyle 属性设置为的组件csOwnerDrawFixed 我实现了绘图项一切工作正常
  • 每次 TDbGrid 的选定位置更改时都会触发什么事件?

    我的项目中有一个 TDbGrid 每次更改所选行时我都试图触发一个事件 行中的任何更改都已经更新了链接到同一数据源的所有数据感知控件 但还需要进行其他更改 我需要一个事件处理程序 我认为 OnColEnter 会起作用 根据帮助文件 它在以

随机推荐

  • 如何使用tcl中的puts更改文本颜色

    我想通过使用 tcl 中的 put 命令来更改控制台中显示的文本颜色以简化调试 我看到很多文章是 abt tk 而不是 tcl 仅供参考 我在 Windows 7 上使用 Active tcl 我尝试过其他人提供的以下代码 http www
  • MySQL 5.1 中需要一个抽象触发器来更新审核日志

    我需要一种方法来检查表中已更改的任何条目并将其传递到审核日志中 它需要从表结构中抽象出来 例如 CREATE TRIGGER table1 update BEFORE UPDATE ON table1 FOR EACH ROW BEGIN
  • 我如何摆脱这个 unicode 字符?

    Any idea how to get rid of this irritating character U 0092 from a bunch of text files I ve tried all the below but it d
  • 如何迭代对象数组以进行预输入?

    http angular ui github io bootstrap http angular ui github io bootstrap 我想使用引导程序的预输入 并在对象中搜索两个不同的密钥对 如何迭代数组对象 另外有人可以解释一下
  • Git 可以忽略内容相同但时间戳更新的文件吗

    我在最近的网络项目中使用 FTP 我尝试使用 git 在 FTP 上保留所有更改的本地备份 FTP 服务器似乎无法支持 MFMT 命令 或者我犯了一些其他错误 下载的文件不保留其时间戳 当我对新下载的文件进行 git diff 时 Git
  • sudo pecl 在 os x lion 上安装 apc 错误

    我尝试在 OS X Lion 上使用 pecl 安装 APC sudo pecl install apc 并且它抱怨缺少 pcre h 文件 In file included from private tmp pear temp APC a
  • JavaScript typeof 曾经返回过“数组”吗?

    我在各种开源项目中都看到过这种习惯用法 it instanceof Array typeof it array 我知道后半部分在 ECMAScript 5 或 6 中不可能是真的 但是是否有一个实现可以从 typeof 返回 数组 或者这是
  • $this->getRequest()->isPost() 返回 false

    我正在处理一个现有代码 最后一个开发人员创建了一个表单 但没有使用 form 代码是 public function indexAction objRequest this gt getRequest var dump objRequest
  • 使用 split_part 后替换空字段中的值

    我有两列 id integer and version text 我正在尝试将字符串转换为version转换为整数 以便我可以选择 id 的最大 最新 版本 然而 第一个实例id将自身存储为version 例子 id version 10
  • 在 C++ WIN32 中识别后台进程并将其带到前台

    谁能告诉我如何识别特定的后台进程 即已经运行的应用程序 并将其带到前台 例如 如果记事本应用程序在后台运行 当我运行 WIN32 应用程序时 它应该识别记事本应用程序 并且记事本应该弹出或进入前台 我尝试了 SwitchToThisWind
  • 如何更改 unsigned char 中的 4 位?

    unsigned char adata unsigned char malloc 500 sizeof unsigned char unsigned char single char adata 100 如何更改 single char 中
  • 如何追查 Wildfly 8.2.0.Final 中不起眼的 HA 集群错误

    设置 我有一个 Wildfly 8 2 0 Final 应用程序服务器 使用 full ha 配置文件在域模式下运行集群 该集群由两个 Wildfly 实例组成 主实例和从实例 每个实例都运行在自己的虚拟机上 应用程序 我的项目作为 war
  • Perl 中字符串的长度与字符编码无关

    长度函数假设汉字超过一个字符 如何在 Perl 中独立于字符编码确定字符串的长度 将中文字符视为一个字符 The length http perldoc perl org functions length html函数对字符进行操作 而不是
  • PHP 正则表达式句点

    如何在 PHP 正则表达式中添加句点 代码中的使用方式是 echo preg match d 1 645 matches 但显然那个时期 645 不被认可 请求有关如何开展这项工作的提示 Since 是一个特殊字符 你需要转义它才能真正得到
  • 在 Swift 子类中添加便捷初始化器

    作为学习练习 我正在尝试实现一个子类SKShapeNode它提供了一个新的方便的初始值设定项 它接受一个数字并构造一个 ShapeNode 它是数字宽度和高度的正方形 根据斯威夫特书 https developer apple com li
  • Python 2.7:附加到字典键的列表值

    我有以下数据 data 1 2 1 3 1 4 2 1 2 2 2 3 我想创建一个包含键列表值的字典 如何通过字典理解来做到这一点 i e 1 2 3 4 2 1 2 3 我已尝试以下操作 但列表在每次迭代时都会被覆盖 x y for x
  • bash中如何通过另一个变量获取一个变量?

    我在 bash 中有三个数组 arr1 arr2 arr3 arr2 1 2 3 4 arr3 6 7 8 9 How can I get a element of arr2 by arr1 like below arr1 0 0 To g
  • 大端和小端有点混乱

    我正在从这个网站上阅读有关小端和大端表示的内容http www geeksforgeeks org little and big endian mystery http www geeksforgeeks org little and bi
  • 如何将非 www 流量重定向到 CloudFront 后面的 EC2 实例上托管的网站的 www?

    我在 CloudFront 后面的单个 EC2 实例上托管一个网站 需要将所有非 www 流量重定向到 www 从 SO 上的其他 Q A 中 我能够在 Route53 上配置 A 记录 以将流量从 example com 重定向到 www
  • 对于类运算符,是否允许对其自身进行隐式类型转换?

    我有一个记录 看起来像 TBigint record PtrDigits Pointer lt The data is somewhere else Size Byte MSB Byte Sign Shortint class operat