如何初始化var Record参数

时间:2017-01-26 15:26:39

标签: 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), 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参数会更好吗(因为函数没有读取数据)?

1 个答案:

答案 0 :(得分:5)

仅使用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

如果您的记录包含托管和非托管类型的混合,那么情况就不那么好了。

{$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参数的更多信息,请访问:What's the difference between "var" and "out" parameters?