【问题标题】:Segmentation fault in easy Delphi program in Linux - Windows is fineLinux中简单的Delphi程序中的分段错误-Windows很好
【发布时间】:2021-07-18 15:46:17
【问题描述】:

我有这个简单的程序,用 Delphi 10.2 编写,在 Windows 上运行良好,但在 Linux 上崩溃。

本质是使用的类在其析构函数中具有要执行的代码。

type
  Kwak = class
  public
    index: integer;
    constructor Create(index:integer);
    destructor Free;
  end;

constructor Kwak.Create(index:integer);
begin
  self.index := index;
  writeln('Welcome Kwak '+inttostr(index));
end;

destructor Kwak.Free;
begin
  writeln('Bye Kwak '+inttostr(index));
end;

如果我在调用过程中使用它,比如这个:

procedure myProc1;
var 
  myKwak:Kwak;
begin
  myKwak := Kwak.Create(15);
  myKwak.Free;
end;

这在 Windows 上运行良好,但在 Linux 上会在myKwak 离开范围时导致分段错误(endmyProc1 中遇到)。

我猜这一切都与 Linux 编译器上的自动引用计数有关。

如果我使用FreeAndNil(),程序不会崩溃,但也不会调用析构函数。

什么是优雅的解决方案?

  • 在我的程序中有很多类似的Free。当然,将Free 代码转移到其他东西是可能的,但我希望它更优雅。
  • 程序需要在 Windows 中编译回 XE2,在 Linux 10.2 上。我读到 10.3 省略了 ARC,这可能会解决问题,但 10.3 的成本很高。
  • 需要更改程序,最好尽量减少{$IFDEF ...} 指令。

请告诉我你的建议。

【问题讨论】:

  • Destroy() 定义(并覆盖)为析构函数,而不是Free()。尽管如此,调用Free() 来销毁您的实例是正确的。见this example

标签: linux windows delphi delphi-10.2-tokyo


【解决方案1】:
destructor Free; // <-- WRONG!

这是错误的。正确的析构函数被称为Destroy(),它在TObject 中是virtual,所以你需要在派生类中override 它:

type 
  Kwak = class
  public
    index: integer;
    constructor Create(index:integer);
    destructor Destroy; override;
  end;

constructor Kwak.Create(index:integer);
begin
  inherited Create;
  self.index := index;
  writeln('Welcome Kwak '+inttostr(index));
end;

destructor Kwak.Destroy;
begin
  writeln('Bye Kwak '+inttostr(index));
  inherited;
end;

在非 ARC 系统上,TObject.Free() 是一个非虚拟实例方法,如果 Self 不是 nil,则调用 Destroy() 析构函数。

在 ARC 系统上,编译器会默默地将所有对 Free() 的调用替换为 nil 赋值,从而减少对象的引用计数。这样就可以在 ARC 和非 ARC 系统上使用具有相似语义的相同代码。对象的 Destroy() 析构函数在其引用计数降至 0 时被调用。

【讨论】:

  • 值得注意的是,从 10.3 Rio 开始,linux 编译器具有 ditched ARC 并且正在回归传统的内存管理(以镜像 Windows 编译器)。在这一点上,升级并忘记 ARC 几乎是值得的,因为它无论如何都会消失。并不是说它会影响此代码,但如果 OP 的其余代码依赖 ARC 进行内存管理,那么升级到东京以外的地区将需要重大的重构。
  • @J... ARC 已经消失了,就像10.4 ditched ARC for ALL platforms
  • 确实,我注意到 Tokyo/Rio 是因为 OP 正在使用 Linux,但是是的,ARC 完全是一条死胡同。也许“离开”是一个糟糕的措辞——我的意思是从 OP 的角度来看他们的升级前景。现在投资于 ARC 相关代码的新开发只是在挖一个技术债务漏洞。
  • 感谢 Remy 将析构函数替换为销毁(覆盖)使其像魅力一样工作。非常感谢您的帮助。
猜你喜欢
  • 1970-01-01
  • 2012-09-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多