FreeAndNil的问题

程晨c 2012-02-04 09:44:31
一个frmMain为MDIForm,一个form1为MDIChild,
点击frmMain上有一个btn1按钮,btn1的单击事中件代码 if Form1=nil then form1:=TForm1.Create(nil); Form1.Show;
在form1的close事件中代码 FreeAndNil(form1);
form1上有一个btn1按钮,btn1的单击事中件代码 Self.Close;

frmMain具体代码如下

procedure TfrmMain.btn1Click(Sender: TObject);
begin
if Form1=nil then form1:=TForm1.Create(nil);
Form1.Show;
end;


form1具体代码如下

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
FreeAndNil(form1);
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
Self.Close;
end;



问题是,如果通过单击Form1窗体右上角自带的关闭按钮来关闭窗体,则不报错。
如果通过单击Form1上的btn1按钮来关闭窗体,则报如下错误


为什么两个关闭方法一个正常一个却报错呢?
...全文
273 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
Jekhn 2012-02-04
  • 打赏
  • 举报
回复
CSDN就可以,在我的社区,我的资源里面,你把积分设置为0就行了,这样下载就不用积分了。
程晨c 2012-02-04
  • 打赏
  • 举报
回复
回复Jekhn:
上传到CSDN什么位置呢?
我上传后,你下载看一看,看在你的机器上是否报错。
谢谢!
程晨c 2012-02-04
  • 打赏
  • 举报
回复
回复Jekhn:

上传到CSDN什么位置呢?
我上传上,你下载看一看,看在你的机器上是否也报错。
谢谢!
Jekhn 2012-02-04
  • 打赏
  • 举报
回复
我是在D7下测试的,要不你把你的工程打包上传到CSDN,可能跟你的某些设置也有关系,或者按照我跟你说的用自带的MDI APP试一下。
程晨c 2012-02-04
  • 打赏
  • 举报
回复
回复Jekhn:

你用的delphi的版本是7.0的么?

我将
if Form1=nil then form1:=TForm1.Create(nil);
改为
if Form1=nil then form1:=TForm1.Create(Application);

点击Form1的btn1关闭Form1时,仍报错!
程晨c 2012-02-04
  • 打赏
  • 举报
回复
关于delphi Assigned

1.根据 Delphi 指令参考手册中

说明:
Assigned 函式在参数不为nil时传回True,表示指针已经指到某个内存地址,这个内存地址可能是一个对象地首地址,也可能在函数或过程中,声明一个指针变量,没有赋值为nil ,无乱的指向某处,这两个种情况,Assigned(指针变量)都不为nil , 函数放回True;

而参数为nil时则传回False。


Assigned 并不是一个真正的函数。

技巧:
用呼叫 Assigned 的方式来取代直接把参数拿来和nil比较,效率会更好。


2.这个问题要从内存方面来解释
当你建构一个物件 SomeComponet.Create(Owner);
系统会有一个指针指向这个对象
当你解构一个物件 SomeComponet.Free;
系统会将指针指到的东西杀掉,但是指针还是指在相同的位置
请注意计算机的资源是有限的,
所以可能下一步你的程序要跟系统要资源,
刚才的指针位置,就出现了其它的数据
If Assigned(SomeComponet) then SomeComponet := nil;
先检查这个对象有没有在其它地方被设成 nil,
然后再将它设成 nil 。


3
function Assigned(var P): Boolean;

Description

Use Assigned to determine whether the pointer or procedure referenced by P is nil. P must be a variable reference of a pointer or procedural type. Assigned(P) corresponds to the test P<> nil for a pointer variable, and @P <> nil for a procedural variable.

Assigned returns False if P is nil, True otherwise.

检查指针指向的参考变量或过程是否为nil

每次我通常的处理方法都是:

if assigned(frm) then frm.close; 但是当下次调用时就会出错。为什么呢,
frm.close;frm.free; 只是指定这块内存可以重写,并未释放为NIL 因此当下次调用时,即使frm.free已经
执行过,assigned(frm)仍为TRUE,再次释放 frm.Close 或者 frm.free 肯定会报错;因为frm.Close或frm.free 是释放对象指针frm 指向的内存空间,在上次已经释放调了,但是 frm 本身并没有 初始化为 nil ,相反它还是指向被释放的内存地址;东西已经没有了,没有地东西去释放,不报错错才怪。

正确的处理方法:

if assigned(frm) then
begin
frm.close;
frm:=nil;
end;

或:

if assigned(frm) then
begin
frm.close;
freeandnil(frm);
end;




chinawcs 2012-02-04
  • 打赏
  • 举报
回复
Assigned 这个不知道吗 ?

相当于nil 判断
程晨c 2012-02-04
  • 打赏
  • 举报
回复
请教chinawcs:


if not Assigned(FrmOrd) then
begin
Application.CreateForm(TFrmOrd, FrmOrd);
FrmOrd.Show;
end;


Assigned是什么功能函数呢?
Jekhn 2012-02-04
  • 打赏
  • 举报
回复
试了一下,问题出在TForm1.Create(nil)把它改为TForm1.Create(Application);至于为什么会报错不太清楚,建议楼主用D自带的MDI APP生成一个试一下,在New->Others->Projects里面就有MDI Application,里面在创建MDI Child的时候Owner也是设置为Application。另外个人觉得在Close里面用FreeAndNil(form1);去释放对象的方式感觉不太好,FreeAndNil一般是在外部调用的,很少在类内部使用。
chinawcs 2012-02-04
  • 打赏
  • 举报
回复
再mdiform 里 调用与销毁是 这样的

//主窗体调用
if not Assigned(FrmOrd) then
begin
Application.CreateForm(TFrmOrd, FrmOrd);
FrmOrd.Show;
end;

//子窗体销毁
procedure FrmOrd.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
FrmOrd:= nil;
end;



程晨c 2012-02-04
  • 打赏
  • 举报
回复
现在改成
if Form1=nil then form1:=TForm1.Create(nil);
也不报错了

估计是delphi生成的exe跟windows的兼容性的问题吧。搞不清了。
程晨c 2012-02-04
  • 打赏
  • 举报
回复
奇怪了,我重新打开,运行测试,又不报错了。
程晨c 2012-02-04
  • 打赏
  • 举报
回复
是啊,我也是D7,真是奇怪了!
Jekhn 2012-02-04
  • 打赏
  • 举报
回复
在D7测试的,你用的也是D7吧
Jekhn 2012-02-04
  • 打赏
  • 举报
回复
奇怪了,在我这里测试完全没有问题的。
程晨c 2012-02-04
  • 打赏
  • 举报
回复
回复Jekhn:已经上传了。

5,392

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧