在 Delphi 中,如何修复 64 位发布版本中 FreeAndNil 的访问冲突(当 64 位调试版本有效时)?
In Delphi, how to fix access violation on a FreeAndNil in 64-bit release build (when 64-bit debug build works)?
这是我的问题的一些简化代码上下文:
TSomeone = record
FirstName: String;
LastName: String;
Picture: TGraphic;
end;
TSomeoneHelper = record helper for TSomeone
public
procedure Clear();
procedure LoadFromFile(const Filename: String);
end;
procedure TSomeoneHelper.Clear();
begin
Self.FirstName := '';
Self.LastName:= '';
try
if Assigned(Self.Picture) then
FreeAndNil(Self.Picture); // <---- Crash here in 64-bit release
except
Self.Picture := nil;
end;
end;
通常有人会声明一个TSomeone
变量,然后调用myVar.LoadFromFile('myfile.blah')
来填充记录。在 LoadFromFile
过程中创建了一个 TJPEGImage
(TGraphic
后代),然后分配给 Picture
.
因为我不在 class 中(record helper
中没有构造函数)我无法将 Picture
初始化为 nil
。因为 FreeAndNil
崩溃。奇怪的是,在 32 位构建中,它似乎初始化为 nil
,但在 64 位构建中它不是(它是 "Inaccessible value")。出于这个原因,我添加了 try except
。但在 64 位版本中更奇怪的是,我遇到了 try except
.
未捕获的访问冲突
总结一下:
- 32 位版本 + 调试版本都可以,因为
Picture
被初始化为 nil
因为魔法 (?),所以没有例外 - 一切都很好
- 64 位调试
Picture
已初始化 "Inaccessible value" 触发 Assigned
然后 FreeAndNil
发生访问冲突但 try
捕获它所以一切都是好
- 64 位版本(不知道如何调试 CPU 程序集所以不确定会发生什么)但是
try
没有捕捉到访问冲突并且错误被抛出到用户太差了
我该怎么做才能解决这个问题?
它在构建类型和体系结构之间的工作方式不同这一事实纯属运气。这在任何地方都不起作用(OP 评论只是证实了我的想法)。
如果使用 Delphi 10.4+,则使用 Custom Managed Records 将(非托管)var 初始化为 nil
,并且 Assigned()
调用不会造成访问冲突。
最后我只是重构了我的代码以使用 类 而不是记录。在构造函数中,我将 var 初始化为 nil
。它更干净,可以与 any 版本的 Delphi.
一起使用
这是我的问题的一些简化代码上下文:
TSomeone = record
FirstName: String;
LastName: String;
Picture: TGraphic;
end;
TSomeoneHelper = record helper for TSomeone
public
procedure Clear();
procedure LoadFromFile(const Filename: String);
end;
procedure TSomeoneHelper.Clear();
begin
Self.FirstName := '';
Self.LastName:= '';
try
if Assigned(Self.Picture) then
FreeAndNil(Self.Picture); // <---- Crash here in 64-bit release
except
Self.Picture := nil;
end;
end;
通常有人会声明一个TSomeone
变量,然后调用myVar.LoadFromFile('myfile.blah')
来填充记录。在 LoadFromFile
过程中创建了一个 TJPEGImage
(TGraphic
后代),然后分配给 Picture
.
因为我不在 class 中(record helper
中没有构造函数)我无法将 Picture
初始化为 nil
。因为 FreeAndNil
崩溃。奇怪的是,在 32 位构建中,它似乎初始化为 nil
,但在 64 位构建中它不是(它是 "Inaccessible value")。出于这个原因,我添加了 try except
。但在 64 位版本中更奇怪的是,我遇到了 try except
.
总结一下:
- 32 位版本 + 调试版本都可以,因为
Picture
被初始化为nil
因为魔法 (?),所以没有例外 - 一切都很好 - 64 位调试
Picture
已初始化 "Inaccessible value" 触发Assigned
然后FreeAndNil
发生访问冲突但try
捕获它所以一切都是好 - 64 位版本(不知道如何调试 CPU 程序集所以不确定会发生什么)但是
try
没有捕捉到访问冲突并且错误被抛出到用户太差了
我该怎么做才能解决这个问题?
它在构建类型和体系结构之间的工作方式不同这一事实纯属运气。这在任何地方都不起作用(OP 评论只是证实了我的想法)。
如果使用 Delphi 10.4+,则使用 Custom Managed Records 将(非托管)var 初始化为 nil
,并且 Assigned()
调用不会造成访问冲突。
最后我只是重构了我的代码以使用 类 而不是记录。在构造函数中,我将 var 初始化为 nil
。它更干净,可以与 any 版本的 Delphi.