大家看一下下面的代码,如果调用test方法,仍然会抛出异常,请问是为什么?procedure throw;
begin
  try
    raise Exception.Create( 'test' );
  except
    on e: Exception do
    begin
      raise e;
    end;
  end;
end;procedure test;
begin
  try
    throw;
  except
    on e:Exception do
      AddMsg( e.Message );
  end;
end;然而改一下,就没问题了procedure throw;
begin
  try
    raise Exception.Create( 'test' );
  except
    on e: Exception do
    begin
      raise;      //这里改成这样
    end;
  end;
end;procedure test;
begin
  try
    throw;
  except
    on e:Exception do
      AddMsg( e.Message );
  end;
end;

解决方案 »

  1.   

    楼主后面的写法表示把在throw过程中try...except捕获到的异常向外“重新抛出”,当然又会被test中的try...except捕获到再次处理,相当于下面这样procedure test;
    begin
      try
        raise Exception.Create( 'test' );
      except
        on e: Exception do
          AddMsg( e.Message );
      end;
    end;
    而上面一种写法中所抛出的异常经过throw中的try...except处理后,异常对象e就会被自动销毁。此时再在test中尝试访问e对象,会遇到“内存越界”错误,因为此时e已经不存在了Delphi中的异常对象在被处理后就会自动销毁,除非它被重新抛出。
    重新抛出的语句就是raise;
      

  2.   

    我的问题是,第二次捕捉异常后,正常情况下应该不会保存,实际上报错了
    你说如果raise就不会报地址错,我用的不正是raise吗?
      

  3.   

    可以这么理解:
    第一种写法throw.except捕捉到异常e后,如果没有使用继承raise(raise后不加参数)而是raise在后跟了其它值的时候(包括raise e),会先把e标志成已经捕捉到过的异常。这样,下次捕捉到异常之前,首先会清理标为已捕捉到过的异常的对象,从而避免memory leak。于是在test.except中,捕捉到的异常对象实际上已经被销毁了,test.except结束后试图清理异常对象e时,又会因为该对象销毁已经被销毁了而产生另外一个异常,也就是说,在你的test.except结束时,发生了一个你没预料到的异常而第二种写法直接将继承上一次异常,与第一种写法引发的方式不同,不把这个对象标志成已捕捉过的,于是下次捕捉异常之前就不会试图清理它实际上的处理机制远比我说的复杂许多(比如不是通过标记异常对象本身来确定是否释放它的,而是通过不同的引发调用方式实现的),不过发生的顺序大体上没问题,这样只是有助于理解而已
      

  4.   

    从最常见的写法:raise Exception.Create('xxx')可以看出,raise的异常对象必须是一个新对象,然后IDE会在处理它后进行施放