Delphi 中使用单个函数释放内存和 nil

发布于 09-13 21:46 字数 496 浏览 6 评论 0原文

我有很多内存分配和相同数量的 FreeMem 调用。但我没有在调用 freemem 之前进行检查以查看指针是否为零,以及在释放后将指针设置为 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、常规指针等)。

我可以做什么来解决这个问题?有更好的解决方案吗?

I have a lot of memory allocations and the same number of FreeMem calls. What I didn't have though is a check before calling freemem to see if the pointer was nil, and a line after freeing to set the pointer to nil.

I tried to create a function to do this

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;

But there's a problem. It can't set the origional pointer to nil because the parameter isn't variable (var p: Pointer). I can't use var though because if I do the compiler complains the type has to be the exact same type (Pointer). The pointers I'm passing could be pointers to any type (PChar, regular pointer, etc.).

What can I do to fix this? Is there a better solution?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

秋心╮凉2024-09-20 21:46:40

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

您在该函数中做了一些毫无意义的事情。

首先,释放 nil 指针总是安全的,因此在调用 FreeMem 之前没有理由检查这一点。它释放了您需要担心的非零指针,但没有任何函数可以保护您免受这种情况的影响。

接下来,FreeMem 的大小参数多年来一直被忽略。过去,如果您提供该参数,它需要与传递给 GetMem 的大小相匹配,但现在,FreeMem 完全忽略该参数 - 编译器甚至不将该参数传递给函数。

考虑到上述所有内容,您的函数可以归结为:

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

小心不要意外地在任何不是用 GetMem 分配的指针的地方调用该函数。编译器不会像您使用类型化参数那样为您捕获它。如果您尝试释放未使用 GetMem 分配的内容,您可能会收到 EInvalidPointer 异常,但之后您传入的变量仍将为 nil。这与 FreeAndNil 的工作方式相同。

To be able to pass arbitrary pointer values to that function, you need to follow the same model as FreeAndNil and pass in an untyped parameter. Otherwise, the compiler correctly complains about actual and formal parameter types not being identical. Type-cast the untyped parameter to Pointer when you call FreeMem on it.

You're doing a couple of pointless things in that function.

First of all is that freeing a nil pointer is always safe, so there's no reason to check for that before calling FreeMem. It's freeing a non-nil pointer that you need to worry about, but no function can protect you from that.

Next, the size parameter to FreeMem has been ignored for many years. It used to be that if you provided that parameter, it needed to match the size passed to GetMem, but nowadays, FreeMem completely ignores that parameter — the compiler doesn't even pass that parameter to the function.

With all of the above in mind, your function boils down to this:

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

Be careful not to accidentally call that function on anything that isn't a pointer allocated with GetMem. The compiler won't catch it for you like it could if you were using typed parameters. If you attempt to free something that wasn't allocated with GetMem, you'll probably get an EInvalidPointer exception, but the variable you passed in will still be nil afterward. That's the same way FreeAndNil works.

宁愿没拥抱2024-09-20 21:46:40

SysUtils 中有一个名为 FreeAndNil 的过程可以对对象执行此操作。它通过使用一个无类型的 var 参数来实现这一点,并将该参数转换为 TObject,并且由您来确保不向其传递非 TObject 的内容。如果需要的话,您可以在这里做类似的事情。只是要小心;如果你这样做,就没有类型安全。

There's a procedure in SysUtils called FreeAndNil that does this for objects. It does it by using an untyped var parameter which it casts to TObject, and it's up to you to ensure you don't pass it something that's not a TObject. You could do something similar here if you needed to. Just be careful; there's no type safety if you do that.

年少掌心2024-09-20 21:46:40

就像 Mason Wheeler 所说,你应该使用与 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;

--jeroen

PS:Rob Kennedy 在 非类型化 var 参数,该参数具有指向互联网上非类型化参数页面的链接。

PS2:供参考: SysUtils.pas 的 Kylix 版本已上线,其中的 FreeAndNil 与 Delphi 中的相同。

Like Mason Wheeler said you should use the same trick as FreeAndNil in the SysUtils unit does on object references.
So I modified your code, unit tested it, and this works fine:

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 wrote a nice answer on untyped var parameters that has a link to his untyped parameter page on the internet.

PS2: For reference: The Kylix version of SysUtils.pas is on-line, and the FreeAndNil there is identical to how it is in Delphi.

稳稳的幸福2024-09-20 21:46:40

我经常使用 ReallocMem 来进行指针/内存操作。

调用

ReallocMem(P,0)

会将指针设置为 Nil。

关于使用它你需要知道的一件事是,P 在传递给 ReallocMem 之前需要初始化。

I tend to work with ReallocMem a lot for pointer/memory operation.

Calling

ReallocMem(P,0)

will set the pointer to Nil.

1 thing you need to know about using it, P needs to be initialized before being passed to ReallocMem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文