是这样的:
你新建一个Application,凡一个按钮,然后在里面写代码如下:
procedure TForm1.ButtonClick(Sender:TObject);
var
  AButton:TButton;
begin
  AButton.Free;
end;
运行之后,点击按钮,主窗体就会Free掉。但是程序还在运行!

解决方案 »

  1.   

    这个bug早就有好多人讨论过了。
      

  2.   

    这个也不能算bug,abutton是局部变量,delphi编译器也没有对它初始化
    不知道abutton指向什么地方的情况下,调用free。这就是典型的c语言中wild pointer带来的不可预计的后果,delphi不应该对其负责。
      

  3.   

    确实是Kingron老大说的那样
    在调用ButtonClick时,因为Delphi默认是FastCall调用,而ButtonClick为TForm1的方法,所以EAX即为Self值,
    而一句AButton.Free,CPU窗口看到的就为Call TObject.Free
    也就相当于Form1.Free,可以这样看
    procedure TForm1.ButtonClick(Sender:TObject); 
    var 
    AButton:TButton; 
    begin 
      ShowMessage(AButton.Name);
    end; 很有意思的阿
    procedure TForm1.ButtonClick(Sender:TObject); 
    var 
    AButton:TButton; 
    begin 
      AButton.Caption := 'xzgyb';
      ShowMessage(AButton.Name);
    end;
    如果在AButton.Free后加一ShowMessage(AButton.Name)则释放掉的是Button1, 当然这也会出错
    都是编译器的东西,不懂
      

  4.   

    这哪里是什么bug?????没有给AButton局部变量申请空间,赋给其合理的引用,在进入当前方法,在栈上分配空间,局部变量的值是随机的,一般来说是上一次运行或者上一次栈上的方法(当然此时已经收回,但是里面残留的值还在),内存残留的信息,也就是说什么值都可能。我试过了,什么情况都会出现,有时 出现AV错误,有时恰好是 Button1的引用
    有时是Form1的引用,我想大家再追究 Button1,Form1的引用怎么恰好到了第一个
    局部变量里面,就有点舍本逐末了。这不是bug,假如我用汇编 乱改TObject的VMT,程序出错,也能怪编译器不的是么
    ??
      

  5.   

    我觉得这其实就是编译器优化的结果,如果这样
    {$o-}
    procedure TForm1.ButtonClick(Sender:TObject); 
    var 
    AButton:TButton; 
    begin 
      AButton.Free;
    end; 
    {$o+}
    大部分情况下会出错而默认被编译器优化了,就有一条AButton.Free;
    编译器就不会在堆栈上递减ESP来产生一局部变量
    而调用AButton.Free,用的EAX就是调用ButtonClick传过来的SELF
      

  6.   

    这个问题恐怕要到Borland新闻组去查查资料了,或者问一下,应该有满意的答案。
      

  7.   

    引发这个Bug的原因非常清晰,是指针没有促使化。我用的Delphi5,仅仅发生于优化编译。
    究其原因是因为,因为由于AButton没有被赋过值,一直是无效的,所以编译器会删除这个变量定义。这样就导致函数没有局部变量,也就没有了进入代码和退出代码。同时,AButton.Free也将会删除对AButton的引用,直接调用Free函数。而Free函数也是没有参数的,它只需要一个隐含的变量Self。而类成员函数调用默认都是把Self存放于EAX中。这样,调用OnClick时,Form被作为Self传入,而现在又被传入到Free函数中。因此会造成父窗口的Free。
    如果在AButton前加一个对AButton读取的应用,就会迫使函数添加一段初始化代码,比如:
    ShowMessage(IntToHex(Integer(AButton), 8));
    这时候,AButton的位置正好相当于Sender,就可以把Button给Free掉。另外我这边用不优化方式编译,AButton正好为nil,因此不会有任何反应。
      

  8.   

    强烈支持xzgyb(老达摩)的观点,这个问题是由于寄存器EAX引起的,而不是堆栈。仔细看了一下,好像是Delphi对变量应用次数判断出现了问题,如果只使用了一次,Delphi是不会认为变量分配空间,使用两次以上则会。估计是Delphi认为第一次应该是赋值,后面才是读取,因此,有效的使用至少回有两次访问。如果只访问了一次,就删除它。
      

  9.   

    鼓掌~~~~~~~`GoodHope!!!!!!!!!
    还有人要继续吗?
      

  10.   

    GoodHope说得非常精彩!!!!!!!
    可以结贴了。
      

  11.   

    我还想补充一下,Delphi的优化似乎是首先刨去无效的语句,然后再删掉无效的变量声明。比如如下语句:
    var
    AButton: TButton;
    BButton: TButton;
    begin
    AButton := BButton;
    BButton.Free;
    end;
    BButton使用了两次,应该为它分配空间,而AButton只用了一次,应该是A无效,B有效。但实际上两个都被清除了。这是因为对于赋值语句,如果被赋值地变量在随后没有被引用,或立即又被赋值。这一个赋值语句会被删除,又只剩下BButton.Free了。
    但是如果在AButton := BButton;换成:
    AButton.Caption := '@#$%';
    这下就相当于A对应Form,B对应Button了。原因也类似。
    考虑下面两段代码效果也有点意思。 AButton.Caption := '@#$%';
    BButton := AButton;
    BButton.Free; AButton.Caption := '@#$%';
    BButton := AButton;
    BButton.Free;
      

  12.   

    漏了一句:优化在语法检查之后进行(因为即使是无效语句也必须语法正确),所以删除变量的定义,不会导致Delphi在应用变量的地方报错。不过Delphi明显应该应该删掉整句话,而不仅仅是这个变量的引用。估计是因为整句删除的检查已经做过了。
      

  13.   

    http://www.csdn.net/expert/topic/583/583855.xml?temp=.1804926
    你们都可以去看一看吗?我知道你们都是高手,不过,别笑可不可以?
      

  14.   

    GoodHope,你来的少,因此是三角,好像分数要足够高~~~~~~~~~:)