Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何初始化var记录参数_Delphi_Delphi 7 - Fatal编程技术网

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
变量被实现为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 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)作为一般解决方案?有没有一个通用的解决方案?是的,我说过你可以做到。答案和我上面的评论都很清楚。输入常量的好提示!