Ver Mensaje Individual
  #12  
Antiguo 19-08-2008
Avatar de cHackAll
[cHackAll] cHackAll is offline
Baneado?
 
Registrado: oct 2006
Posts: 2.159
Reputación: 22
cHackAll Va por buen camino
Esperando no complicar mas las ideas voy aclarando algunas dudas; try crea una instruccion de "salto en caso de error", obviamente "salta" a la primera instruccion de su respectivo finally ejecutando su contenido hasta end; cada try genera un salto distinto para permitir al desarrollador un control más especifico para cada posible error, por ello desde el punto de vista de compilación los casos anidado y "compacto" generan un codigo binario distinto.

Si la excepción es generada dentro del constructor, el valor retornado por el mismo es nulo (puesto que falló durante la creación de la nueva instancia), por ende, el llamado al método en memoria 0.Destroy ó 0.Free generan el mismo error de acceso a una zona de memoria vacía.

Código Delphi [-]
uses SysUtils; {$apptype console}
 
var Saved: procedure;
 
procedure OnExit;
begin
 ReadLn; // antes que la consola se cierre por la excepción, 
            // esperaremos a que el usuario vea los mensajes y pulse {ENTER}
 Saved;
end;
 
type
 TThrow = class // (TObject), clase base...
  procedure Throw;
  constructor Create;
  destructor Destroy; override;
 end;
 
procedure TThrow.Throw; asm dd 0F4F6E432h end; // provocamos una división por cero.
 
constructor TThrow.Create;
begin
 inherited;
 WriteLn(Self.ClassName + '();'); // mostramos un mensaje para notificar que el constructor hizo su gracia.
end;
 
destructor TThrow.Destroy;
begin
 WriteLn('~' + Self.ClassName + '();'); // para notificar que el destructor hizo lo suyo.
 inherited;
end;
 
type
 TFirst = class(TThrow); // heredamos...
 TSecond = class(TThrow);
 
var
 a, b: TThrow;
 
begin
 @Saved := ExitProc;
 ExitProc := @OnExit;

 {$define anidado} // Comenta esta línea para probar un try..finally NO anidado.

 {$ifdef anidado}
 try
  a := TFirst.Create;
  // ...
  a.Throw;
  // ...
  try
   b := TSecond.Create;
   // ...
   b.Throw;
   // ...
  finally
   b.Destroy;
  end;
 finally
  a.Destroy;
 end;
 {$else}
 try
  a := TFirst.Create;
  // ...
  a.Throw;
  // ...
  b := TSecond.Create;
  // ...
  b.Throw;
  // ...
 finally
  a.Destroy;
  b.Destroy; // aquí el detalle... aún no ha sido construido "b", generamos una nueva excepción
 end;
 {$endif}
end.

En el anterior ejemplo he "sacado" la generación de la excepción del constructor, para demostrar que entre el codigo inicial de Roman y último no es relevante la construcción del objeto, si no el orden construcción/excepción de los objetos.

En el caso anidado el control es mayor y más estructurado, como resultado obtenemos un EDivByZero que era justamente lo esperado... lo que difiere al comentar la directiva de precompilación, " // {$define anidado}" obteniendo un EAccessViolation al intentar destruir un objeto "inexistente".

Podriamos hacer otro ejemplo no OO, talvez ordenes de apertura y cerrado de archivos de paginación... en tal caso obtendriamos un resultado que al igual que en el ejemplo depende de la estructura del codigo.

Saludos
__________________
RTFM > STFW > Foro > Truco > Post > cHackAll > KeBugCheckEx

Última edición por dec fecha: 19-08-2008 a las 03:21:50.
Responder Con Cita