我有记录类型:
type
TIPInfo = record
IP,
HostName,
City,
Region,
Country,
Loc,
Org: WideString
end;
Run Code Online (Sandbox Code Playgroud)
函数返回记录数据:
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;
Run Code Online (Sandbox Code Playgroud)
呼叫者,召集者:
var
IPInfo: TIPInfo;
if GetPublicIPInfo(IPInfo) then... // use data
Run Code Online (Sandbox Code Playgroud)
它是var TIPInfo通过调用初始化的正确方法FillChar还是应该将每个字段设置为空字符串?来电者应该这样做吗?
此外,out在案例中使用参数会更好吗(因为函数不读取数据)?
FillChar在这里使用just 是错误的.如果任何WideString成员不是空的,那么你会以这种方式泄漏它们.相反,我建议如下:
Finalize(IPInfo);
FillChar(IPInfo, SizeOf(TIPInfo), 0);
Run Code Online (Sandbox Code Playgroud)
或者另一种方法是将默认记录定义为类型化常量:
const
DefaultIPInfo: TIPInfo = ();
Run Code Online (Sandbox Code Playgroud)
然后你可以使用简单的赋值:
IPInfo := DefaultIPInfo;
Run Code Online (Sandbox Code Playgroud)
在现代版本的Delphi中,您可以使用这个更易读的代码:
IPInfo := Default(TIPInfo);
Run Code Online (Sandbox Code Playgroud)
有关此特定主题的更多信息,请参阅以下主题:
请注意,代码中的泄漏很难找到,因为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.
Run Code Online (Sandbox Code Playgroud)
输出是:
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.
Run Code Online (Sandbox Code Playgroud)
输出是:
Foo 42 42
仅默认为out参数初始化托管成员.因此,最好的办法是默认自己初始化变量,即使它是作为out参数传递的.
有关out参数的更多信息,请参见:"var"和"out"参数之间的区别是什么?
| 归档时间: |
|
| 查看次数: |
740 次 |
| 最近记录: |