Delphi 中使用单个函数释放内存和 nil
我有很多内存分配和相同数量的 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 技术交流群。
发布评论
评论(4)
就像 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 在 非类型化 var 参数,该参数具有指向互联网上非类型化参数页面的链接。
PS2:供参考: SysUtils.pas 的 Kylix 版本已上线,其中的 FreeAndNil 与 Delphi 中的相同。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
为了能够向该函数传递任意指针值,您需要遵循与 FreeAndNil 相同的模型并传递非类型化参数。否则,编译器会正确地抱怨实际参数类型和形式参数类型不相同。当您调用 FreeMem 时,将非类型化参数类型转换为 Pointer。
您在该函数中做了一些毫无意义的事情。
首先,释放 nil 指针总是安全的,因此在调用 FreeMem 之前没有理由检查这一点。它释放了您需要担心的非零指针,但没有任何函数可以保护您免受这种情况的影响。
接下来,FreeMem 的大小参数多年来一直被忽略。过去,如果您提供该参数,它需要与传递给 GetMem 的大小相匹配,但现在,FreeMem 完全忽略该参数 - 编译器甚至不将该参数传递给函数。
考虑到上述所有内容,您的函数可以归结为:
小心不要意外地在任何不是用 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:
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.