RM.*_*RM. 6 delphi pointers interface access-violation
我在以下代码中收到意外的访问冲突错误:
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.
Run Code Online (Sandbox Code Playgroud)
我知道接口应该以不同的方式使用.但是我正在研究使用这种方法的遗留代码库.而且我很惊讶地发现,保留SizeOf(ITest)内存并将ITest放在那里是不够的.
现在有趣的是,如果我改变第一行
GetMem(p, 21);
Run Code Online (Sandbox Code Playgroud)
比AV消失了.(20个字节或更少的失败).对此有何解释?
(我使用的是Delphi XE2 Update 4 + HotFix)
请不要评论代码是多么可怕或建议如何正确编码.请回答为什么有必要保留21个字节而不是SizeOf(ITest)= 4?
Rem*_*eau 25
你有效写的是在幕后做以下逻辑:
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;
Run Code Online (Sandbox Code Playgroud)
GetMem()不保证将其分配的内容归零.当您将新对象实例分配给可变的接口时,如果字节不是零,则RTL将认为已存在现有接口引用并将尝试调用其_Release()方法,从而导致AV,因为它不受真实对象的支持实例.您需要预先将分配的字节清零,然后RTL将看到一个nil接口引用而不再尝试调用其_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.
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
638 次 |
| 最近记录: |