Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 20-12-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Estudiando constructores y destructores

Segun la documentacion, en el constructor de un objeto todas las referencias a otros objetos son asignadas automaticamente a NIL

Es decir, teniendo esta clase

Código Delphi [-]
  TTestClass = class
  public
    Object: TObject;
  end;

procedure Test;
var
  LTest: TTestClass;
begin
  LTest := TTestClass.Create;
  LTest.Object ---> NIL

  LTest.Object.Free --> Llamada segura, Free va a chequear que el objeto no es nil y no se ejecuta el destructor, no hay riesgo de Acess Violation
end;

Esto funciona de maravillas y no he tenido nunca problemas con eso (una vez que lo entendi claro)

Hasta que hoy, haciendo experimentos raros, se me ocurrio hacer esto:

Código Delphi [-]
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    FormFoo: TObject;
  end;

procedure TForm2.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  FormFoo.Free;

  LocalFoo.Free;
end;

Obviamente llamar a FomFoo.Free es seguro, de hecho el destructor no se ejecuta; las variables de instancia son seteadas a nil en los constructores de los objetos (que va, TForm es un objeto tambien, recuerda? )

Pero el problema son las variables locales; es verdad, de hecho tiene logica, que si yo declaro una variable, y no la inicializo nunca, el valor no esta definido; es decir que una llamada a Free deberia arrojar una excepcion Acess Violation. Bueno, curiosa fue mi sorpresa al correr el codigo anterior: no se elevo ninguna excepcion.

Los invito a que ejecuten el mismo codigo

Para el que no se le ocurra, puede agregar la linea ShowMessage(LocalFoo.ClassName); antes del Free
Responder Con Cita
  #2  
Antiguo 21-12-2015
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Lo he ejecutado.
No se elevan excepciones pero se corrompe la app.
Si tratas de hacer esto:
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
  S: String;
begin
  FormFoo.Free;
  LocalFoo:= nil;
  S:= LocalFoo.ClassName;
  MessageBox(0,0,PCHAR(S),0);
  LocalFoo.Free;
end;

Aparece una excepcion en la línea
Código Delphi [-]
S:= LocalFoo.ClassName;

Si trato de hacer esto
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  FormFoo.Free;
  LocalFoo:= nil;
  ShowMessage(LocalFoo.ClassName);
  LocalFoo.Free;
end;
El antivirus se carga el ejecutable y no corre.


Saludos.
Responder Con Cita
  #3  
Antiguo 21-12-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Curiosamente, usando el codigo que publicas me da error de access violation, como debe ser

Entonces creo que habra que hilar mas fino: Uso Delphi 2010 y estoy corriendo Windows 10 64 bits

En esas condiciones este codigo:

Código Delphi [-]
procedure TForm2.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  FormFoo.Free;

  LocalFoo.Free;
end;

Ejecuta sin problemas: lo que me causo tanta curiosidad es que el Button1 del form desaparecia...entonces, agregando el ShowMessage:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  FormFoo.Free;
  ShowMessage(LocalFoo.ClassName);
  LocalFoo.Free;
end;

El mensaje imprime "TButton"

Mas extraño aun, puedo hacer esto sin problemas:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  LocalFoo.Free;
  ShowMessage(LocalFoo.ClassName);
end;

No da error Access Violation!!! No puede ser!! Me imprime "TButton"!

Las variantes son infinitas:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
begin
  LocalFoo.Free;
  ShowMessage(TButton(LocalFoo).Caption); // imprime "Button1"
end;
Responder Con Cita
  #4  
Antiguo 21-12-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Código Delphi [-]
uses
  Rtti;

var
  X: Integer = 1;
  Y: Integer = 1;

procedure TForm1.Button1Click(Sender: TObject);
var
  LocalFoo: TObject;
  Ctx: TRttiContext;
  T: TRttiType;

  FooParentClassName: string;
  AClass: TClass;
  Button2: TButton;
begin
  LocalFoo.Free;
  FooParentClassName := LocalFoo.ClassParent.ClassName;
  AClass := LocalFoo.ClassType;
  T := Ctx.GetType(AClass);

  Button2 := T.GetMethod('Create').Invoke(AClass, [Self]).AsObject as TButton;
  Button2.Parent := Self;
  Button2.Top := Y * 10;
  Button2.Left := X * 25;
  Inc(X);

  if Button2.Left + Button2.Width >= Width then
  begin
    X := 1;
    Inc(Y, 4);
  end;

  Button2.Caption := FooParentClassName;
  Button2.OnClick := Button1Click;
end;

Este codigo crea un boton con caption "TCustomButton", lo coloca en el formulario, y destruye a Button1.
A su vez, asigno el mismo evento que puedo ir invocando una y otra vez y nunca se produce ninguna Access Violation
Responder Con Cita
  #5  
Antiguo 21-12-2015
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola Agustin.
Cita:
Empezado por AgustinOrtu Ver Mensaje
...
Pero el problema son las variables locales; es verdad, de hecho tiene logica, que si yo declaro una variable, y no la inicializo nunca, el valor no esta definido; es decir que una llamada a Free deberia arrojar una excepcion Acess Violation. Bueno, curiosa fue mi sorpresa al correr el codigo anterior: no se elevo ninguna excepcion.
A mi modo de ver, LocalFoo.Free no genera una excepción por que cuando se declara una variable local (en la pila), Delphi no inicializa la referencia y tiene un valor que apunta a una dirección indeterminada, normalmente basura (aunque excepcionalmente podría ser nil).

Por otro lado el método TObject.Free está implementado así,
Código Delphi [-]
procedure TObject.Free;
begin
  if Self <> nil then Destroy;
end;
pero por ser LocalFoo una variable local y no estar inicializada, no tendrá el valor nil sino garbage y se llamará al método Destroy sobre la dirección del invocante (Sender en el caso).

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalObj: TObject;
begin
  if LocalObj = Sender then ShowMessage('LocalObj referencia lo mismo que Sender');
  LocalObj.Free; // igual que: Sender.Free
end;

Es por eso que se insiste en inicializar las variables locales:
Código Delphi [-]
procedure TForm1.Button2Click(Sender: TObject);
var
  LocalObj: TObject;
begin
  LocalObj := nil;
  if LocalObj = Sender then ShowMessage('LocalObj es Sender'); // no se muestra el mensaje,
  LocalObj.Free;                                               // y nada raro sucede
end;
Hay casos como el tipo string donde no es necesaria la inicialización, aunque hacerlo no provoca perjuicio alguno.

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #6  
Antiguo 21-12-2015
Avatar de AgustinOrtu
[AgustinOrtu] AgustinOrtu is offline
Miembro Premium
NULL
 
Registrado: ago 2013
Ubicación: Argentina
Posts: 1.858
Poder: 15
AgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en brutoAgustinOrtu Es un diamante en bruto
Yo creo que hay algo mas

No esta apuntando a garbage como decis: creo que por alguna feliz coincidencia, siempre apunta a Sender

Creo que tiene que ver con el codigo que emite el compilador; desgraciadamente, no soy capaz de leer lenguaje ensamblador


Código Delphi [-]
var
  Local: TObject;
begin
  Local.Free; // acesss violation aca
  ShowMessage(Local.ClassName);
  Button1.Visible := True; // comentando esta linea, desaparece el access violation
end;
Responder Con Cita
  #7  
Antiguo 21-12-2015
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola Agustin.
Cita:
Empezado por AgustinOrtu Ver Mensaje
Yo creo que hay algo mas

No esta apuntando a garbage como decis: creo que por alguna feliz coincidencia, siempre apunta a Sender

...
No parece ser así en todos los casos, por ejemplo reduciendo el código a esto,
Código Delphi [-]
...
procedure TForm1.Button1Click(Sender: TObject);
var
  LocalObj: TObject;
begin
  LocalObj.Free;
end;

end.
cierra Form1 y deja el proyecto residente en memoria.

No sé con seguridad que valor tiene la variable LocalObj al momento de la llamada a Free, pero sin dudas que inicializando la variable local no se produce ninguna anomalía.

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Constructores FairyLady OOP 14 24-11-2011 22:24:05
Sobrecarga de constructores vejerf OOP 2 06-06-2008 12:52:36
Como usar los formularios MDI, constructores de componentes Narlohe OOP 3 11-12-2006 10:54:10
Dudas de como seguir estudiando Gabel Varios 9 14-08-2006 20:33:44
constructores Dantael OOP 2 25-01-2004 23:57:50


La franja horaria es GMT +2. Ahora son las 02:16:40.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi