gpt4 book ai didi

delphi - 存储 Delphi 接口(interface)引用时出现奇怪的 AV

转载 作者:行者123 更新时间:2023-12-03 14:55:15 25 4
gpt4 key购买 nike

我在以下代码中收到意外的访问冲突错误:

program Project65;

{$APPTYPE CONSOLE}

{$R *.res}

uses
SysUtils;

type
ITest = interface
end;

TTest = class(TInterfacedObject, ITest)
end;

var
p: ^ITest;

begin
GetMem(p, SizeOf(ITest));
p^ := TTest.Create; // AV here
try
finally
p^ := nil;
FreeMem(p);
end;
end.

我知道接口(interface)应该以不同的方式使用。不过,我正在开发一个使用这种方法的遗留代码库。我非常惊讶地发现,保留 SizeOf(ITest) 内存来放置 ITest 是不够的。

现在有趣的是,如果我将第一行更改为

GetMem(p, 21);

然后 AV 就消失了。 (20 字节或更少失败)。对此有何解释?

(我正在使用 Delphi XE2 Update 4 + HotFix)

请不要评论代码有多糟糕或建议如何正确编码。相反,请回答为什么需要保留 21 个字节而不是 SizeOf(ITest) = 4?

最佳答案

您有效编写的内容是在幕后执行以下逻辑:

var
p: ^ITest;
begin
GetMem(p, SizeOf(ITest));
if p^ <> nil then p^._Release; // <-- AV here
PInteger(p)^ := ITest(TTest.Create);
p^._AddRef;
...
if p^ <> nil then p^._Release;
PInteger(p)^ := 0;
FreeMem(p);
end;

GetMem() 不保证将其分配的内容清零。当您将新对象实例分配给接口(interface)变量时,如果字节不为零,RTL 会认为已经存在一个现有的接口(interface)引用,并会尝试调用其 _Release() 方法,从而导致AV 因为它没有真实对象实例的支持。您需要事先将分配的字节清零,然后 RTL 将看到 nil 接口(interface)引用,并且不再尝试调用其 _Release() 方法:

program Project65;

{$APPTYPE CONSOLE}

{$R *.res}

uses
SysUtils;

type
ITest = interface
end;

TTest = class(TInterfacedObject, ITest)
end;

var
p: ^ITest;

begin
GetMem(p, SizeOf(ITest));
try
FillChar(p^, SizeOf(ITest), #0); // <-- add this!
p^ := TTest.Create; // <-- no more AV
try
...
finally
p^ := nil;
end;
finally
FreeMem(p);
end;
end.

关于delphi - 存储 Delphi 接口(interface)引用时出现奇怪的 AV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10988787/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com