关闭窗体时内存报错

7年 2009-03-17 04:40:46
showmodal显示窗体,关闭时内存报错。请问各位知道原因么?
创建的时候用的
if not assigned(form1) then
begin
form1:=Tform1.create(application);
form1.showmodal;
end;
关闭时在close里写
action:=cafree;
form1:=nil;
各位帮忙看看。
...全文
233 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
hduhjh 2009-03-18
  • 打赏
  • 举报
回复
[Quote=引用 26 楼 Seamour 的回复:]
引用 21 楼 hduhjh 的回复:
if Assigned(Form1) then

if Form1 <>nil then

Assigned是判断指针所指向的内容是否为空。如果Form1指向的内容(即对象)被释放,但没有把Form1赋成nil的话,则会出现下列的情况:
Assigned(Form1)返回false
而Form1 <>nil返回true
可见是不等价的...

为啥这么多人喜欢乱讲呢,你试过自己说的么?Assigned(p) 完全等价于 p <>nil,你觉得能delphi通过什么机制…
[/Quote]

你自己试试有没有Form1赋成nil的结果再来说
Seamour 2009-03-18
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 hduhjh 的回复:]
if Assigned(Form1) then

if Form1 <>nil then

Assigned是判断指针所指向的内容是否为空。如果Form1指向的内容(即对象)被释放,但没有把Form1赋成nil的话,则会出现下列的情况:
Assigned(Form1)返回false
而Form1 <>nil返回true
可见是不等价的...
[/Quote]
为啥这么多人喜欢乱讲呢,你试过自己说的么?Assigned(p) 完全等价于 p<>nil,你觉得能delphi通过什么机制检查出一个地址是不是被“释放”了?


[Quote=引用 23 楼 zzflover 的回复:]
1:按F7单步执行时,怎么能跳出第三方控件的代码,转到自己的代码里去。
2:if not assigned(form1) then form1:=Tform1.create(application) 和 with TForm1.Create(self)的区别。
[/Quote]
1. 删掉编译好的dcu,用 dcc32.exe -q *.pas -z -$D- 重新编译
2. 如果是关于with,随便找本书应该都有说;如果是问TForm.Create(AOwner: TComponent)的差别,那么见vcl源代码

constructor TComponent.Create(AOwner: TComponent);
begin
FComponentStyle := [csInheritable];
if AOwner <> nil then AOwner.InsertComponent(Self);
end;

也就是说,当指定为AOwner的控件被释放的时候,该控件也被释放了。虽然一般情况下ShowModal里不会放什么奇怪的代码,Create(Self/Application/nil)看起来没什么差别(一般都是在窗体事件中,Self指向的是一个TForm的继承对象),但是像下面这段代码就可以挂掉用Create(Self)的程序(由于模式窗体的作用,程序将没法再得到响应):

{Unit1.pas}
...
implementation

uses
Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
if(not Assigned(Form2))then
Form2 := TForm2.Create(Application);
Form2.Show;
end;

=================================================
{Unit2.pas}
...
implementation

uses
Unit3;

procedure TForm2.Button1Click(Sender: TObject);
begin
with TForm3.Create(Self) do { 换成Application/nil则没问题 }
try
ShowModal;
finally
Free;
end;
end;

=================================================
{Unit3.pas}
...
implementation

uses
Unit2;

procedure TForm3.Button1Click(Sender: TObject);
begin
FreeAndNil(Form2);
end;

ps:使用环境为d7。如果设计vcl的时候考虑到的话,也有较复杂的办法可以避免这种情况发生,不知道后面版本的delphi有没有在vcl中“修正”这个“bug”
hduhjh 2009-03-18
  • 打赏
  • 举报
回复
Tform1.create(application) 和 TForm1.Create(self)

所有者,没什么大区别.做下简单试验就知道了
Allan_xd 2009-03-18
  • 打赏
  • 举报
回复
再考虑一下其它原因,问题不在这段代码上,可能是有些对象没有析构或什么的。把窗口中的其它必须执行的代码先注释掉不出错后再慢慢恢复。

上面的方法我放在另一个帖中,没被人重视。楼主为什么不重建一个新form,把你说的那些认为有问题的代码写进去看会不会出错,不要无原则的试来试去。
7年 2009-03-18
  • 打赏
  • 举报
回复
1:按F7单步执行时,怎么能跳出第三方控件的代码,转到自己的代码里去。
2:if not assigned(form1) then form1:=Tform1.create(application) 和 with TForm1.Create(self)的区别。
7年 2009-03-18
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 skertone 的回复:]
这类用一次就丢的标准代码为

同时将其从工程的自动创建列表中去掉

with TFormX.Create(self) do
try
Showmodal;
finally
Free;
end;
[/Quote]
用8楼的可以了,不报错了,谢谢。
再问几个问题哈。
hduhjh 2009-03-18
  • 打赏
  • 举报
回复
if Assigned(Form1) then

if Form1<>nil then

Assigned是判断指针所指向的内容是否为空。如果Form1指向的内容(即对象)被释放,但没有把Form1赋成nil的话,则会出现下列的情况:
Assigned(Form1)返回false
而Form1<>nil返回true
可见是不等价的,如果Form1是一个全局变量的话,释放Form1用Form1.free是不严格的,应该用FreeAndNil(Form1);
7年 2009-03-18
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 hduhjh 的回复:]
1: assigned(form1) 窗体没nil掉就会异常
2:不大可能
3:OnClose事件里写个Realse;方便简单
[/Quote]
问题
1:还是不打明白。希望能详细点说明。
2:按F7单步执行时,怎么能跳出第三方控件的代码,转到自己的代码里去。
3:明白了。
hduhjh 2009-03-18
  • 打赏
  • 举报
回复
Release;//手误
hduhjh 2009-03-18
  • 打赏
  • 举报
回复
1: assigned(form1) 窗体没nil掉就会异常
2:不大可能
3:OnClose事件里写个Realse;方便简单
7年 2009-03-18
  • 打赏
  • 举报
回复
看了各位的说法,有点疑问:
1: if not assigned(form1) then //不要用這種方法判斷。
为什么不能用这种方法判断?
2:我的程序中有第三方控件,是不是有可能是因为第三方控件的原因才导致内存错误?
3:如果是show窗体的话。该怎么释放?
Seamour 2009-03-18
  • 打赏
  • 举报
回复
你要我试啥?你的命题是:
Assigned(p) 和 p<>nil 不等价,按照你的说法,会出现 Assigned(Form1)为False 并且 Form1<>nil为True 的情况
还是你构造一个这种情况出来吧

要不,我这儿给您一段代码,您亲自试试看自己是不是胡说?

procedure TForm1.Button1Click(Sender: TObject);
const
B2S : array[Boolean]of string = ('False', 'True');
var
o : TObject;
begin
o := TButton.Create(nil);
o.Free;
Memo1.Lines.Add(B2S[Assigned(o)]);
Memo1.Lines.Add(B2S[o<>nil]);
end;

Seamour 2009-03-17
  • 打赏
  • 举报
回复
真了不起,您自己胡说八道了一堆,连oo的基本机制都没搞清楚,还反过来让别人去读源代码

[Quote=引用 11 楼 Avan_Lau 的回复:]
form1:=nil;
要寫在ondestroy事件里面
begin
inherited;
form1:=nil;
end;

設定cafree後-----調用release--->free---->構造函數Destroy,這里會去遍歷application,執行removecomponent,將自己從components屬性list中移除。
所以你在之后設定form1:=nil,執行free時,不會觸發destroy,會造成components無法被正確維護,在之后的訪問過程中,就出現地址訪問非法的問題。所以應該寫在ondestroy里面。
[/Quote]

[Quote=引用 14 楼 Seamour 的回复:]
你觉得 OnDestroy 事件里的 inherited 会执行什么?procedure FormDestroy(Sender: TObject) 和 destructor Destroy 之间是什么关系?
像下面的 Free 能触发 destructor Destroy 么?会出任何现访问错误么?
[/Quote]
答案是:Destroy是Destroy,FormDestroy是FormDestroy,两者没关系,OnDestroy里写一句inherited什么都不会发生。delphi的对象不需要靠外部变量去维护,它自己可以通过Self指针正确处理。后面我举的几个例子就是为了说明,不论什么何时设定 form1:=nil 甚至不要form1这个变量,都不会影响vcl的运作机制。所以你说的一堆不会触发这个那个,什么不会被正确维护、地址访问错误之类的都是扯淡,谁希罕跟您“发飚”么?
金卯刀 2009-03-17
  • 打赏
  • 举报
回复
楼上的,
1、先搞清楚我要说的是什么,application只是一个例子,因为是作为参数传进取,只要是Tcomponent类型的!
2、把相关源代码先看清楚;
3、要驳倒我的观点,请拿出具有可比性的东西!

不要在没搞清问题前就在这“发飚”,我可没那么多时间陪你 耍
Seamour 2009-03-17
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 Avan_Lau 的回复:]
form1:=nil;
要寫在ondestroy事件里面
begin
inherited;
form1:=nil;
end;

設定cafree後-----調用release--->free---->構造函數Destroy,這里會去遍歷application,執行removecomponent,將自己從components屬性list中移除。
所以你在之后設定form1:=nil,執行free時,不會觸發destroy,會造成components無法被正確維護,在之后的訪問過程中,就出現地址訪問非法的問題。所以應該寫在ondestroy里面。
[/Quote]
不知道说啥好了……

你觉得 OnDestroy 事件里的 inherited 会执行什么?procedure FormDestroy(Sender: TObject) 和 destructor Destroy 之间是什么关系?
像下面的 Free 能触发 destructor Destroy 么?会出任何现访问错误么?

form1 := nil;
with TForm1.Create(Application) do
try
ShowModal;
finally
end;
...

procedure TForm1.FormClose(Sender: TObject);
begin
form1 := nil; {*}
Free; { 已经在设计期使 OnClose = FormClose }
end;

如果前面用 form1 := TForm1.Create(Application),那么*那句会造成什么影响?

或者

program Project1;

uses
Forms,
Unit1;

procedure CreateMainForm;
var t: Cardinal;
begin
Application.CreateForm(TForm1, t);
end;

begin
Application.Initialize;
CreateMainForm;
Application.Run;
end.


unit Unit1;

interface

uses
Forms;

type
TForm1 = class(TForm)
end;

implementation

{$R *.dfm}

end.


{==== Unit1.dfm ====}
object blah: TForm1
end

像这样的程序能正确执行么?会有什么诸如Application无法正确维护出现访问错误的不良后果么?
btw,注意在 Unit1 中连 var Form1: TForm1 的声明都没有
yct0605 2009-03-17
  • 打赏
  • 举报
回复
代码没有问题,楼主检查一下其他的代码吧。
金卯刀 2009-03-17
  • 打赏
  • 举报
回复
上面說的“遍歷application”,是因為你create時傳的是appllication
金卯刀 2009-03-17
  • 打赏
  • 举报
回复
form1:=nil;
要寫在ondestroy事件里面
begin
inherited;
form1:=nil;
end;

設定cafree後-----調用release--->free---->構造函數Destroy,這里會去遍歷application,執行removecomponent,將自己從components屬性list中移除。
所以你在之后設定form1:=nil,執行free時,不會觸發destroy,會造成components無法被正確維護,在之后的訪問過程中,就出現地址訪問非法的問題。所以應該寫在ondestroy里面。

建議在create對象時,能不傳參數就不傳,傳nil。這樣效能上面肯定比較好,因為不必再去維護owner.components。
hduhjh 2009-03-17
  • 打赏
  • 举报
回复

form1.showmodal;
//直接跟free就好了
//Showmessage('什么时候下去'); 你会发现窗体关闭后才往下走
form1.free;
starluck 2009-03-17
  • 打赏
  • 举报
回复
[Quote=引用楼主 zzflover 的帖子:]
showmodal显示窗体,关闭时内存报错。请问各位知道原因么?
创建的时候用的
if not assigned(form1) then
begin
form1:=Tform1.create(application);
form1.showmodal;
end;
关闭时在close里写
action:=cafree;
form1:=nil;
各位帮忙看看。
[/Quote]

if not assigned(form1) then //不要用這種方法判斷。

form1:=nil; // 在類的關閉事件裏,不要帶入引用變量。


不過你上面的代碼應該是沒有錯的。 你貼出錯來,應該是別的地方引起的。
加载更多回复(8)

5,388

社区成员

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

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