Delphi 如何初始化var记录参数
我有记录类型:Delphi 如何初始化var记录参数,delphi,delphi-7,Delphi,Delphi 7,我有记录类型: type TIPInfo = record IP, HostName, City, Region, Country, Loc, Org: WideString end; 返回记录数据的函数: function GetPublicIPInfo(var IPInfo: TIPInfo): Boolean; begin // initialize FillChar(IPInfo, SizeOf(TIPInfo),
type
TIPInfo = record
IP,
HostName,
City,
Region,
Country,
Loc,
Org: WideString
end;
返回记录数据的函数:
function GetPublicIPInfo(var IPInfo: TIPInfo): Boolean;
begin
// initialize
FillChar(IPInfo, SizeOf(TIPInfo), 0);
// populate data
IPInfo.IP := GetVallue('ip');
IPInfo.HostName := GetVallue('hostname');
IPInfo.City := GetVallue('city');
// etc...
Result := IsOk;
end;
呼叫者:
var
IPInfo: TIPInfo;
if GetPublicIPInfo(IPInfo) then... // use data
调用FillChar
初始化var TIPInfo
是正确的方法,还是应该将每个字段设置为空字符串?打电话的人应该这样做吗
另外,在这种情况下使用
out
参数是否更好(因为函数没有读取数据)?仅使用FillChar
在这里是错误的。如果任何WideString
成员不是空的,那么您将以这种方式泄漏它们。相反,我建议如下:
Finalize(IPInfo);
FillChar(IPInfo, SizeOf(TIPInfo), 0);
或者,另一种方法是将默认记录定义为类型化常量:
const
DefaultIPInfo: TIPInfo = ();
然后您可以使用简单的赋值:
IPInfo := DefaultIPInfo;
在Delphi的现代版本中,您可以使用以下可读性更强的代码:
IPInfo := Default(TIPInfo);
有关此特定主题的更多信息,请参阅以下主题:
WideString
变量被实现为COMBSTR
对象,并在COM堆上分配。因此,如果对Delphi内存管理器使用内存泄漏检测,则不会检测到泄漏,因为它是从不同的堆泄漏的
在您的情况下,因为您的记录是托管类型,并且只包含托管类型,所以您可以使用out
参数来获得良好的效果。对于托管类型,out
参数意味着编译器将在调用站点生成代码,以便在传入记录之前默认初始化记录
考虑以下计划:
{$APPTYPE CONSOLE}
type
TRec = record
Value: WideString;
end;
procedure Foo1(var rec: TRec);
begin
end;
procedure Foo2(out rec: TRec);
begin
end;
procedure Main;
var
rec: TRec;
begin
rec.Value := 'Foo';
Foo1(rec);
Writeln(rec.Value);
Foo2(rec);
Writeln(rec.Value);
end;
begin
Main;
end.
输出为:
Foo
Foo
42
42
输出为:
Foo
Foo
42
42
福
42
42
对于out
参数,只有托管成员是默认初始化的。因此,您最好的选择是自己默认初始化变量,即使它作为out
参数传递
有关
out
参数的更多信息,请参见此处:当函数未读取参数时,我将使用out参数。同样,在这种情况下,很明显函数本身应该初始化它,而不是调用方。FillChar不会在任何情况下正确初始化托管类型,如字符串(尽管在您的情况下是这样),因此我只需分别初始化每个字段。在这种情况下,所有记录字段都是WideString
,由编译器自动初始化,因此函数根本不需要初始化任何内容。尽管如此,我同意R.贝波尔的观点,使用out
而不是var
是最好的选择。@RemyLebeau成员可以从以前使用该对象获得任意值。所以它们确实需要被分配。@R.Beiboer,你所说的“虽然在你的情况下是这样”是什么意思?@zig当你所有的宽字符串都是空字符串时,FillChar并没有什么坏处。如果分配了其中任何一个字符串,则FillChar不会处理这些字符串。我假设在你的情况下它们是空的,这就是为什么我说“虽然在你的情况下是空的”。此外,我认为您应该接受David的回答,因为他清楚地解释了初始化记录的工作原理以及out和var的用法。因此,您建议始终调用Finalize(IPInfo);FillChar(IPInfo,SizeOf(TIPInfo),0)代码>?我的意见是,您应该编写代码,使其对未来的更改具有健壮性。这意味着默认情况下总是初始化记录,即使它恰好只包含托管类型。如果您获取问题中的记录,那么您可以使用out
参数,并依靠编译器在调用站点默认init。但是,在将来的某一天,您将向记录中添加一个非托管成员,而几英里之外的一些功能将中断。我的观点是,out
几乎是无用的。我再次问:我可以随时调用Finalize(IPInfo);FillChar(IPInfo,SizeOf(TIPInfo),0)代码>作为一般解决方案?有没有一个通用的解决方案?是的,我说过你可以做到。答案和我上面的评论都很清楚。输入常量的好提示!