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

Dai*_*tsu 8 memory delphi parameters memory-management 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;
Run Code Online (Sandbox Code Playgroud)

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

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

Rob*_*edy 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;
Run Code Online (Sandbox Code Playgroud)

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


Mas*_*ler 9

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


Jer*_*ers 6

梅森惠勒说,你应该使用相同的伎俩FreeAndNilsysutils的单位确实对对象的引用.
所以我修改了你的代码,对它进行了单元测试,这很好用:

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;
Run Code Online (Sandbox Code Playgroud)

--jeroen

PS:Rob Kennedy为无类型的var参数写了一个很好的答案,这些参数有一个链接到他在互联网上的无类型参数页面.

PS2:供参考:Kysix 版本的SysUtils.pas是在线的,FreeAndNil与Delphi中的版本相同.