使用单一功能在Delphi中释放内存和nil

时间:2010-08-11 17:27:42

标签: delphi memory memory-management parameters delphi-6

我有很多内存分配和相同数量的FreeMem调用。我没有的是在调用freemem之前检查指针是否为nil,以及释放后将指针设置为nil后的一行。

我尝试创建一个函数来执行此操作

procedure FreeMemAndNil(p: Pointer; size: Integer = -1);
begin
  if p <> nil then
  begin
    if size > -1 then
      FreeMem(p, size)
    else
      FreeMem(p);
    p := nil;
  end;
end;

但是有一个问题。它不能将原始指针设置为nil,因为参数不可变(var p:Pointer)。我不能使用var,因为如果我做编译器抱怨类型必须是完全相同的类型(指针)。我传递的指针可能是指向任何类型的指针(PChar,常规指针等)。

我该怎么做才能解决这个问题?有更好的解决方案吗?

4 个答案:

答案 0 :(得分:13)

为了能够将任意指针值传递给该函数,您需要遵循与FreeAndNil相同的模型并传入无类型参数。否则,编译器会正确地抱怨实际和形式参数类型不相同。当您在其上调用FreeMem时,将无类型参数输入到Pointer。

你在这个功能中做了几件毫无意义的事情。

首先,释放nil指针始终是安全的,因此在调用FreeMem之前没有理由检查它。它释放了一个你需要担心的非零指针,但没有任何功能可以保护你。

接下来,FreeMem的size参数已被忽略多年。过去,如果你提供了这个参数,它需要匹配传递给GetMem的大小,但是现在,FreeMem完全忽略了那个参数 - 编译器甚至没有将该参数传递给函数。

考虑到以上所有因素,您的功能归结为:

procedure FreeMemAndNil(var P);
var
  Tmp: Pointer;
begin
  Tmp := Pointer(P);
  Pointer(P) := nil;
  FreeMem(Tmp);
end;

注意不要在不是分配了GetMem的指针的任何内容上意外调用该函数。如果您使用的是类型化参数,编译器将不会像您一样捕获它。如果你试图释放没有用GetMem分配的东西,你可能会得到一个EInvalidPointer异常,但你传入的变量在之后仍然是零。这与FreeAndNil的工作方式相同。

答案 1 :(得分:9)

SysUtils中有一个名为FreeAndNil的程序可以为对象执行此操作。它是通过使用非强制类型的 var 参数来实现的,它将它强制转换为TObject,并且由您决定不传递它不是TObject的东西。如果需要,你可以在这里做类似的事情。小心点如果你这样做,就没有类型安全。

答案 2 :(得分:6)

Mason Wheeler一样,您应该使用与FreeAndNil单元中的SysUtils相同的技巧来处理对象引用。
所以我修改了你的代码,对它进行了单元测试,这很好用:

procedure FreeMemAndNil(var ptr; size: Integer = -1);
var
  p: Pointer;
begin
  p := Pointer(ptr);
  if p <> nil then
  begin
    if size > -1 then
      FreeMem(p, size)
    else
      FreeMem(p);
    Pointer(ptr) := nil;
  end;
end;

- 的Jeroen

PS:Rob Kennedy在untyped var parameters上写了一个很好的答案,它在互联网上有一个指向他的无类型参数页面的链接。

PS2:供参考:The Kylix version of SysUtils.pas is on-line,FreeAndNil与Delphi中的相同。

答案 3 :(得分:4)

我倾向于使用ReallocMem进行指针/内存操作。

致电

ReallocMem(P,0)

将指针设置为Nil。

使用它需要了解的一件事,P需要在传递给ReallocMem之前进行初始化。