在Ada(2005或2012)中实现相当于java finalize块的最佳实践

Java具有finalize块,允许在块之后执行一些语句 保留(即使引发异常也会执行)。例:
try {
  ...
} catch (Exception e) {
  ...
} finally {
  ... // any code here
}
Ada具有允许实现Finalize操作的受控对象 但是没有与java中相同的finalize块。这对于日志记录非常有用 关闭文件,事务等(无需为每个可能的块创建特定的标记类型)。 你将如何在Ada 2005中实现这样的终结块(同时保持代码可读)? Ada 2012是否有计划允许轻松执行任何终结代码?     
已邀请:
我相信这段代码会按照你的要求行事;它用现在的
raise
return
成功打印出
42
。这是T.E.D建议的实施。 在Mac OS X,Darwin 10.6.0上使用GCC 4.5.0进行测试。
with Ada.Finalization;
package Finally is

   --  Calls Callee on deletion.
   type Caller (Callee : not null access procedure)
      is new Ada.Finalization.Limited_Controlled with private;

private

   type Caller (Callee : not null access procedure)
      is new Ada.Finalization.Limited_Controlled with null record;

   procedure Finalize (Object : in out Caller);

end Finally;


package body Finally is

   procedure Finalize (Object : in out Caller)
   is
   begin
      Object.Callee.all;
   end Finalize;

end Finally;


with Ada.Text_IO; use Ada.Text_IO;
with Finally;
procedure Finally_Demo is
begin

   declare

      X : Integer := 21;

      --  The cleanup procedure, to be executed when this block is left
      procedure F
      is
      begin
         Put_Line ("X is " & Integer'Image (X));
      end F;

      --  The controlled object, whose deletion will execute F
      F_Caller : Finally.Caller (F'Access);

   begin

      X := 42;

      raise Constraint_Error;

   end;

end Finally_Demo;
    
正如Adrien在评论中提到的,
Finalize
更类似于析构函数。 为了得到一些近似于异常/最终序列的东西,你可以沿着这些方向做一些事情(警告,没有编译,只是输入 - 我们将一起解决任何错误:-)另请参阅Ada RM的例外部分。
with Ada.Exceptions;  use Ada.Exceptions;

procedure Do_Something is

   -- Variables and what-not...

   -- In case you have an exception and want to reraise it after you've done
   -- the 'final' processing.
   Exception_Caught : Exception_Occurrence := Null_Occurrence;

begin
   -- You can have some statements, like initializations, here that will not
   -- raise exceptions.  But you don't have to, it can all just go in the
   -- following block. However you want to do it...

   declare
      -- If you need to declare some entities local to a block, put those here.
      -- If not, just omit this declare section.  Be aware, though, that if
      -- you initialize something in here and it raises an exception, the
      -- block's exception handler will not catch it. Such an exception will
      -- propagate out of the whole procedure (unless it has an outermost
      -- exception handler) because you're _not_ in the block's scope yet.

   begin
      -- Main processing that might raise an exception

      ...

   exception
      when E : others =>
         -- Handle any exception that's raised.  If there are specific
         -- exceptions that can be raised, they should be explicitly
         -- handled prior to this catch-all 'others' one.

         -- Save the exception occurrence, i.e. make a copy of it that can
         -- be reraised in the 'Final' section if needed.  (If you want to
         -- reraise for a specific exception, do this in those handlers as
         -- well.
         Save_Occurrence(Exception_Caught, E);

   end;

   -- Final processing. Everything from here to the end of the procedure is
   -- executed regardless of whether an exception was raised in the above
   -- block.  By it including an others handler, it ensured that no exception
   -- will propagate out of this procedure without hitting this 'Final' code.

   -- If an exception was raised and needs to be propagated:
   if Exception_Caught /= Null_Occurrence then
      Reraise_Exception(Exception_Caught);
   end if;

end Do_Something;
    
假设你已经理解了ada.finalization和java中的finalize块之间的区别,我会做类似下面的事情,它应该具有相同的效果。
procedure x is 
begin

  -- some code
  begin
    -- more code (your try)
  exception 
    -- handle exception if necessary (caught exception)
  end;
  -- yet more code which is executed regardless of any exception handling.

end x;
    
Marc C有正确的方法试图在直线程序代码中模拟它。 然而,恕我直言,这种结构主要是一种破解Java的面向对象系统的方法,对于那些希望在老式程序编程中具有OO结构优势的人来说。即使在Java中,你也总是更好地创建一个合适的类。 因此,我认为在Ada中获得该功能的正确方法是制作一个合适的对象,并使你的对象成为ѭ8的孩子,这并不是一件容易的事。 如果你不想打扰创建一个实际的对象,你可以创建一个虚拟对象,将你的终结代码放入其中,然后在你希望它运行的块顶部的堆栈上声明它。缺点是受控类型本身(至少在我上次使用它们时)必须在包级别范围内声明。在这种情况下,您将无法直接引用其中较低声明的对象。他们声称他们将在未来的语言修订中解决这个问题,但我最近没有尝试过,看看他们是否这样做了。     
刚想到另一个答案。它有点沉重(也许比它的价值更麻烦)。但是它会给你一些看起来有点像旧的敲定块的东西 我们的想法是将您的“可终结”代码放入任务中。在任务终止之前,您不能离开作用域的任务。因此,您可以将工作代码放在任务中,并将“最终”代码放在任务定义范围之外。父任务将坐在那里等待工作任务结束(以某种方式),然后它会运行“最终”代码,无论它如何结束。缺点是如果任务抛出异常,它将在任务处停止。因此,您仍然不会获得可以抛出异常的行为,并且在“finalize”代码运行时它会自动传播出去。你可以通过添加一个集合和第二个任务来恢复这种行为(这就是任务的问题。它们就像薯片......你总是需要一个)。
procedure Finalized is
begin
    declare
        task Worker is end Worker;
        task body Worker is begin
            --// Working code in here. Can throw exceptions or whatever. 
            --// Does not matter.
        end Worker;
    begin
    end;

    --// If we get here, we know the task finished somehow (for good or ill)
    --// so the finalization code goes here.

end Finalized;
在我看来,也许有一种方法可以用受保护的对象做这样的事情。我会留下那个让其他人知道的。     

要回复问题请先登录注册