今天,有一个朋友,问了俺一个莫名其妙的问题,问的俺是一愣一愣的,搞了半天愣是没搞明白。他提问的原话是:
一文件流没有创建,怎么判断呢
这个问题还真把我问倒了,我压根就没明白这是个啥意思,后来他说了半天之后,我还是没明白是啥,最后他索性给了一个让我郁闷了半天的代码。如下:
var
Stream : TMemoryStream;
aSkinName : Pchar;
vStrings : TStrings;
begin
inherited ;
vHandle : = LoadLibrary(Pchar(Gv_SkinFile)); // 动态载入DLL,并返回其句柄
// Stream : = TMemoryStream.Create;
try
if vHandle <> 0 then //
begin
@GetSkin: = GetProcAddress(vHandle, ' GetSkin ' );
end ;
if not (@GetSkin = nil ) then
begin
Stream : = TMemoryStream.Create;
aSkinName : = pchar(Gv_SkinName);
GetSkin(aSkinName,Stream);
with Unit_CommonDm.CommonDm.SkinData do
begin
LoadFromStream(stream);
if not Active then Active : = true;
end ;
end else
begin
// RaiseLastWin32Error;
end ;
finally
FreeLibrary(vHandle); // 调用完毕收回DLL占用的资源
stream : = nil ;
if stream = nil then
stream.free;
end ;
stream := nil ;
if stream = nil then
stream.free;
看到这个代码,我还真是郁闷了!后来才明白,原来他是想知道Stream到底有没有被创建过,如果没创建,那么就是个坏指针,是不用释放的。结果给整出来了这么个东西!
起初,我直接说,这个代码肯定报错,但是他反复强调,绝对不错,并且让我试试。于是,我试验了一下,哈,果然不报错啊!我在Delphi中测试的代码如下
var
stream: TMemoryStream;
begin
stream : = TMemoryStream.Create;
stream.Size : = 234 ;
stream : = nil ;
if stream = nil then
stream.Free;
end ;这样写,居然不会出错哦!那么这个创建的TMemoryStream到底释放了没有呢?想都不用想,那是肯定没释放的,也就是说有内存泄露,不信的可以用FastMM查看看。至于为
啥出错,我们需要去看TObject的Destroy的代码,这个在Delphi中式没有实现的,我们在调试过程中打开Delphi的CPU调试窗口查看一下汇编代码
12345678910<pre
class
="brush:delphi">TObject
.
Free:
00403A00 85C0 test eax,eax
//这里检查了释放的指针是否为nil
00403A02
7407
jz
$00403a0b
//如果为nil向后跳7字节,也就是直接跳到ret
00403A04 B201 mov dl,
$01
00403A06 8B08 mov ecx,[eax]
00403A08 FF51FC call dword ptr [ecx-
$04
]
00403A0B C3 ret
</pre>
通过这个反汇编,我们就能明白为啥无论一个对象是否为
nil
都会执行了,主要的就是在释放的时候会先判断一下自身是否为空,不为空的时候才会执行释放操作<br data-filtered="filtered"><br data-filtered="filtered">所以,建议大家在这种情况下,先将以后要判断的对象初始化为
nil
,如果不初始化的话,系统分配给对象变量一个不为
nil
的坏指针,那样后面的判断就失效了,我想我朋友估计<br data-filtered="filtered">也是忽略了这一点吧!<br data-filtered="filtered">
本文转自 不得闲 博客园博客,原文链接: http://www.cnblogs.com/DxSoft/archive/2010/05/17/1737116.html ,如需转载请自行联系原作者