我有记录类型:
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
它是var TIPInfo
通过调用初始化的正确方法FillChar
还是应该将每个字段设置为空字符串?来电者应该这样做吗?
此外,out
在案例中使用参数会更好吗(因为函数不读取数据)?
FillChar
在这里使用just 是错误的.如果任何WideString
成员不是空的,那么你会以这种方式泄漏它们.相反,我建议如下:
Finalize(IPInfo); FillChar(IPInfo, SizeOf(TIPInfo), 0);
或者另一种方法是将默认记录定义为类型化常量:
const DefaultIPInfo: TIPInfo = ();
然后你可以使用简单的赋值:
IPInfo := DefaultIPInfo;
在现代版本的Delphi中,您可以使用这个更易读的代码:
IPInfo := Default(TIPInfo);
有关此特定主题的更多信息,请参阅以下主题:
Delphi"default"关键字,旧版Delphi版本中包含Record类型.
如何在Delphi中正确释放包含各种类型的记录?
请注意,代码中的泄漏很难找到,因为WideString
变量是作为COM BSTR
对象实现的,并在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
如果您的记录包含托管和非托管类型的混合,那么情况就不那么好了.
{$APPTYPE CONSOLE} type TRec = record Value1: WideString; Value2: Integer; end; procedure Foo1(var rec: TRec); begin end; procedure Foo2(out rec: TRec); begin end; procedure Main; var rec: TRec; begin rec.Value1 := 'Foo'; rec.Value2 := 42; Foo1(rec); Writeln(rec.Value1); Writeln(rec.Value2); Foo2(rec); Writeln(rec.Value1); Writeln(rec.Value2); end; begin Main; end.
输出是:
Foo 42 42
仅默认为out
参数初始化托管成员.因此,最好的办法是默认自己初始化变量,即使它是作为out
参数传递的.
有关out
参数的更多信息,请参见:"var"和"out"参数之间的区别是什么?