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
  #41  
Antiguo 07-04-2011
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Thumbs up

Pues aunque no lo creas, yo tampoco conosco una solucion efectiva... . la única solucion que quise implementar fue la siguiente:
Código Delphi [-]
procedure TChildForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
Self:=nil;//lamentablemente en mi delphi 7 ésta instrucion nunca se ejecuta no acabo de entender por qué
end;
Pero como puedes ver en mi Delphi 7 nunca se ejecuta la segunda instruccion, lo cual me parece misterioso, ya que tal solucion es válida para otros lenguajes de programacíon como por ejemplo C++, Java.
Rogaría a algun miembro que tenga las últimas versiones de Delphi a que pruebe y nos comente...
Saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #42  
Antiguo 07-04-2011
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Hola Roberto.

Me resulta algo humorística la forma en que afrontas a Román en los últimos mensajes, pero tal humorismo surge principalmente por la combinación de dos cosas: la idea (interesante, por cierto) de que una clase sea capaz de conocer todas las referencias a sus instancias, y por otro lado, que no pareces tener muy claro lo que Self significa en Delphi (y claro, también por tantas caritas ).

No sé por qué en otros lenguajes se permite la sentencia que señalas (y me gustaría saber), mas en Delphi Self es un parámetro, no declarado, de todos los métodos, y es básicamente la instancia para la cual se está ejecutando el método (intuyo que esto de alguna forma ya lo sabías). Ignoraba que Delphi "permitiese" referencias de escritura en el parámetro Self (para mí siempre ha sido una referencia de solo lectura), pero no me extraña en absoluto que el compilador la deseche sin generar instrucción máquina alguna para esa sentencia (lo puedes verificar con la ventana CPU).

Y es que Self no podría ser variable objeto alguna, todas las variables objeto son punteros (apuntadores) hacia la región de memoria donde se encuentra un "Self", es decir, donde se encuentra una instancia de objeto. Entonces, si se pudiera asignar Nil a Self, lo que se estaría poniendo en blanco sería esa instancia, no las variables que apuntan a ella.

Ahora, aunque hay argumentos muy sólidos para proponer que las clases no conozcan sus instancias y las referencias a éstas, hay casos donde sí pudiera ser conveniente una capacidad similar. Yo tengo una clase derivada de TClientDataSet, con varios métodos que necesitan conocer cuáles otras instancias de la clase comparten la misma base (propiedad DSBase).

Lo solucioné con una lista privada (declarada como variable global en la sección Implementation), y usando el constructor para agregar cada nueva instancia a la lista y el destructor para quitar tal instancia de la lista.
Código Delphi [-]
  Type
    TDataSetList = Class (TList)
      Function GetItem (Const Index :Integer) :TMagiaClientDataSet;
      Property Items [Const Index :Integer] :TMagiaClientDataSet
        Read GetItem; Default;
    End;

  Var
    DataSets :TDataSetList;

...

  Constructor TMagiaClientDataSet.Create (AOwner :TComponent);
  Begin
    Inherited Create (AOwner);
    AutoApplyDetails := True;
    AutoCancelDetails := True;
    AutoEdit := True;
    ChangeCheckFieldTypes := [ftString, ftSmallint, ftInteger, ftWord,
      ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime,
      ftAutoInc, ftFixedChar, ftWideString, ftLargeint, ftVariant, ftGuid,
      ftTimeStamp, ftFMTBcd];

    If DataSets = Nil Then
      DataSets := TDataSetList.Create;

    DataSets.Add (Self);
  End;

  Destructor TMagiaClientDataSet.Destroy;
  Begin
    DataSets.Remove (Self);
    FreeAndNil (FDetailList);
    BlockReadSizeStack.Free;
    FSavePoints.Free;
    Inherited Destroy;
  End;

...

  Function TMagiaClientDataSet.IsBase (Const DataSetIndex :Integer)
    :Boolean;
  Begin
    Result := DataSets [DataSetIndex].DSBase = DSBase;
  End;

...

  Function TMagiaClientDataSet.FindSavePoints
    :TMagiaClientDataSetSavePoints;
  Var
    I :Integer;
  Begin
    If FSavePoints = Nil Then
      For I := 0 To DataSets.Count - 1 Do
        If IsBase (I) And (DataSets [i].FSavePoints <> Nil) Then
        Begin
          Result := DataSets [i].FSavePoints;
          Exit;
        End;

    Result := FSavePoints
  End;

...

Finalization
  DataSets.Free;

Independientemente de lo que dicten los cánones de la POO, esta implementación me resulta eficiente para mis propósitos. Sin embargo, esto es sólo mantener una lista de las instancias creadas de una clase, mas no de las variables que hacen referencia a dichas instancias.

Si quisiéramos que se mantuviera también una lista de tales referencias entraríamos a un terreno un tanto peliagudo, ya que implicaría necesarias modificaciones al compilador Delphi mismo, a fin de que siempre que se ejecute una asignación de instancia de objeto a una variable, tal variable se "marque" para ser limpiada cuando el objeto se destruya:
Código Delphi [-]
Obj1 := TClase.Create...;  // Se "ficha" a Obj1
Obj2 := Obj1;   // Se "ficha" a Obj2
Obj3 := DataSource1.DataSet;  // Se "ficha" a Obj3
...
Obj2.Free;  // Se ponen en blanco (Nil) las variables Obj1 y Obj2
DataSource1.DataSet.Free  // Se pone en blanco (Nil) la variable Obj3

O bien, que no fuese obligatorio "fichar" a la variable, e implementar nosotros mismos un mecanismo "casero" general, con una lista global y una par de funciones AssignObj y FreeObj:
Código Delphi [-]
AssignObj (Obj1, TClase.Create...);  // Se "ficha" a Obj1
AssignObj (Obj2, Obj1);   // Se "ficha" a Obj2
AssignObj (Obj3, DataSource1.DataSet);  // Se "ficha" a Obj3
...
FreeObj (Obj2);  // Se ponen en blanco (Nil) las variables Obj1 y Obj2
Lo pongo como ejemplo, pero lo desaconsejo, porque ¿cómo resolver un caso como este?:
Código Delphi [-]
DataSource1.DataSet.Free;  // Esto NO pondrá en Nil a la variable Obj3

Ahora, sí se realizaran las modificaciones al compilador para que toda asignación de objeto guardara en una lista interna la variable a la cual se asigna, de tal forma que al destruirse tal objeto todas las variables que apunten a él se pongan en Nil, habría que considerar lo mismo para los parámetros de las funciones:
Código Delphi [-]
Procedure X (DataSet :TDataSet;...);
Begin
  If Not DataSet.Active Then
    Exit;
  
  DataSet.Append;
  ...
  ... // Aquí llamada a una rutina que llama a otra que destruye a DataSet
  ... // Aquí el parámetro DataSet deberá volverse Nil
End;
Agrego: Y que las variables y parámetros se eliminaran de dicha lista interna al quedar fuera de ámbito.

Como podrás ver, son varias y muy importantes las implicaciones que tendría modificar el compilador para que las variables objeto nunca apunten a los vestigios de una instancia (es decir, para que se vuelvan Nil cuando la instancia sea destruida).

Pero sí es posible crear una clase particular con este comportamiento, donde esa clase mantenga una lista de punteros, que no serían punteros a las instancias, sino punteros a las variables objeto. De tal forma que el destructor de la clase se encargue de recorrer esa lista y poner a cada variable objeto en Nil. Sin embargo, esto requeriría de un "contrato" entre el creador de la clase y el programador que la usara. Algún párrafo de documentación donde se le diga algo como: Si usted quiere que una variable objeto de esta clase sea limpiada automáticamente, debe usar el método AssignToVar:
Código Delphi [-]
TClase.Create (...).AssignToVar (Obj1);  // En lugar de "Obj1 := TClase.Create (...)"
Obj1.AssignToVar (Obj2);  // En lugar de Obj2 := Obj1;

Yo solía hacerme este tipo de planteamientos casi filosóficos, al grado de crear rutinas de código extravagantes. Con el tiempo uno se va dando cuenta de los pros y contras de cada técnica, hasta que se tiene algún grado de experiencia como para proponer cambios en un lenguaje o en un compilador. Al menos a mí, me gustaría que las clases tuviesen mecanismos nativos para conocer todas sus instancias; pero si esto sonara como un disparate, quizá se deba a que me falta experiencia para darme cuenta de que eso sería un despropósito, o quizá no.

Pero tratándose de variables objetos, creo que lo mejor es seguir dejando la responsabilidad en manos del programador que declara y hace uso de esas variables; algo que me parece Román ya te había comentado.

Un abrazo objetivo.

Al González.

Última edición por Al González fecha: 07-04-2011 a las 23:30:27.
Responder Con Cita
  #43  
Antiguo 08-04-2011
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Cita:
Empezado por Al González Ver Mensaje
.. Ignoraba que Delphi "permitiese" referencias de escritura en el parámetro Self (para mí siempre ha sido una referencia de solo lectura), pero no me extraña en absoluto que el compilador la deseche sin generar instrucción máquina alguna para esa sentencia (lo puedes verificar con la ventana CPU).
...
Muy interesante tu interversion amigo Alberto, para serte franco yo tambien ignoraba la cuestion de que el parámetro Self era solo para lectura, pero la cuestion es que Delphi no se queja al momento de hacer:
Código Delphi [-]
Self:=nil;
Si es solo para lectura y ha sido pensado para eso, pues creo que debería mostrar un error¿verdad? o no permitir directamente tal instruccion y es por eso mi confucion.
Como dije claramente en mi anterior post no tengo una solucion para lo que se pretendía hacer, el hecho de que hubiera hecho uso de Self, fué solo un intento y creo que lo explique claramente. Pero me llama la atencion el código que propones en tu clase "TMagiaClientDataSet"
Código Delphi [-]
Constructor TMagiaClientDataSet.Create (AOwner :TComponent);
  Begin
    Inherited Create (AOwner);
    AutoApplyDetails := True;
    AutoCancelDetails := True;
    AutoEdit := True;
    ChangeCheckFieldTypes := [ftString, ftSmallint, ftInteger, ftWord,
      ftBoolean, ftFloat, ftCurrency, ftBCD, ftDate, ftTime, ftDateTime,
      ftAutoInc, ftFixedChar, ftWideString, ftLargeint, ftVariant, ftGuid,
      ftTimeStamp, ftFMTBcd];

    If DataSets = Nil Then
      DataSets := TDataSetList.Create;

    DataSets.Add (Self);//<- muy pero muy interesate 
  End;
La verdad que me has abierto nuevas perpectivas.., aunque no exactamente siguiende ese mismo camino. por ejemplo:
Cita:
Advertencia:
Lo que voy a exponer a continuacion no significa que pueda llegar a una solucion concreta del tema, sino mas bien hacer conocer una "idea" para quizas poder implementar una solucion desde otro punto de vista.
Todos sabemos que el problema es lo siguiente:
Teniendo creado(instanciado) un formulario de una determinada clase de la siguiente forma:
Código Delphi [-]
if not Assigned(MyForm) then //<- favor poner atencion a ésta linea
   MyForm := TChildForm.Create(Application);//MyForm en una variable privada

MyForm.Show;
y sabiendo que en la clase TChildForm en su evento OnClose tenemos
Código Delphi [-]
procedure TChildForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;//ya sabemos que está linea provocará un liberacion del formulario atraves del método Release.
end;
Ahora el asunto es: ¿cómo lograr saber que el objeto al que hace referencia la variable "MyForm" ha sido liberado?
OJO: todos sabemos que cuando un objeto se libera, pues la referencia que le apuntaba de igual forma sigue referenciando a la misma direccion de memoria donde estaba el objeto.Es decir el espacio de memoria del objeto se libero pero su apuntador(referencia) sigue apuntadolo.
Pues ..en lo anteriores post hemos discutido que la solucion sería poner al apuntador en nulo (nil)despues de la destruccion del objeto y luego para saber si la referencia apunta a un Objeto válido podriamos poner
Código Delphi [-]
if MyForm=nil then
...
o bien usando la funcion Assigned
Código Delphi [-]
if not Assigned(MyForm) then
...
Ahora vá la pregunta ¿Existe alguna forma de determinar que la referencia de un objeto apunta a un objeto no destruido sin estar poniendola a nulo cada vez que se libera el objeto?. Es decir.. yo como programador pienso y digo hipoteticamente:"No quiero que la referencia del objeto se ponga en nulo al momento de destruirse el objeto , más bien quiero que siga apuntado a la misma direccion aunque el objeto ya esté liberado"
Pero si más adelante en mi código quisiera saber si el objeto fue destruido o nó ¿como lo haría? ¿? qué código debiera poner en lugar de
Código Delphi [-]
if MyForm=nil then// éste código ya no serviría ya que MyForm no apunta a nulo pero el objeto ya fué liberado
...
o bien
Código Delphi [-]
if not Assigned(MyForm) then //tampoco sirve
...
¿Cómo lo soluciono?¿Delphi posee algun mecanismo o funcion que me permita solucionarlo?
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #44  
Antiguo 08-04-2011
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 30
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por rgstuamigo Ver Mensaje
[...] Si es solo para lectura y ha sido pensado para eso, pues creo que debería mostrar un error¿verdad? o no permitir directamente tal instruccion [...]
Así es, el compilador no debería permitir esa instrucción, no simplemente ignorarla.

Cita:
Empezado por rgstuamigo Ver Mensaje
Ahora vá la pregunta ¿Existe alguna forma de determinar que la referencia de un objeto apunta a un objeto no destruido sin estar poniendola a nulo cada vez que se libera el objeto?. Es decir.. yo como programador pienso y digo hipoteticamente:"No quiero que la referencia del objeto se ponga en nulo al momento de destruirse el objeto , más bien quiero que siga apuntado a la misma direccion aunque el objeto ya esté liberado"
Pero si más adelante en mi código quisiera saber si el objeto fue destruido o nó ¿como lo haría? ¿? qué código debiera poner en lugar de
Código Delphi [-]
if MyForm=nil then// éste código ya no serviría ya que MyForm no apunta a nulo pero el objeto ya fué liberado
...
o bien
Código Delphi [-]
if not Assigned(MyForm) then //tampoco sirve
...
¿Cómo lo soluciono?¿Delphi posee algun mecanismo o funcion que me permita solucionarlo?
Es interesante lo que planteas y en más de una ocasión me he preguntado cómo resolverlo, ya que Delphi no tiene un mecanismo directo para evaluar si una referencia de objeto es aún válida o un simple puntero hacia donde estuvo una instancia que ya fue destruida.

Pero ahora que vuelvo a leer el planteamiento de parte tuya, recordando que GetMem y FreeMem son las funciones que utiliza nativamente una clase para reservar y liberar el bloque de memoria de la instancia, y que tales funciones son reemplazables , se antoja posible implementar una especie de lista de punteros liberados, para buscar en esa lista la dirección contenida en una variable objeto no Nil, y con ello determinar si se trata de un objeto que ya fue destruido o no.

El inconveniente a resolver sería el de las coincidencias de bloques, es decir, aquellos casos donde una nueva instancia de objeto venga a ocupar la parte inicial (o el bloque de memoria completo) que ocupaba previamente otro objeto ya destruido. Quizá una solución a esto sería hacer que GetMem desplace el bloque que devuelve para que no haya coincidencias o algún control similar, pero eso haría crecer constantemente la memoria usada por la aplicación, por lo que se necesitaría de cierta ayuda de parte del programador, como para decir "estas variables ya no me interesa evaluar", lo cual nos remite, una vez más, a la recomendación de que cada programador se haga responsable de la vida de sus variables objetos.

No obstante el antojo de darle algunas vueltas más la tuerca persiste, e intentar lo que comento de GetMem y FreeMem puede ser cuando menos un ejercicio interesante (sin olvidar que esas funciones no sólo se utilizan para instancias de objetos).

Saludos.

Al González.
Responder Con Cita
  #45  
Antiguo 08-04-2011
Avatar de rgstuamigo
rgstuamigo rgstuamigo is offline
Miembro
 
Registrado: jul 2008
Ubicación: Santa Cruz de la Sierra-Bolivia
Posts: 1.646
Poder: 17
rgstuamigo Va por buen camino
Arrow

Cita:
Empezado por Al González Ver Mensaje
Es interesante lo que planteas y en más de una ocasión me he preguntado cómo resolverlo, ya que Delphi no tiene un mecanismo directo para evaluar si una referencia de objeto es aún válida o un simple puntero hacia donde estuvo una instancia que ya fue destruida.
...
Veo que me has entendido perfectamente....
Cita:
Empezado por Al González Ver Mensaje
Pero ahora que vuelvo a leer el planteamiento de parte tuya, recordando que GetMem y FreeMem son las funciones que utiliza nativamente una clase para reservar y liberar el bloque de memoria de la instancia, y que tales funciones son reemplazables , se antoja posible implementar una especie de lista de punteros liberados, para buscar en esa lista la dirección contenida en una variable objeto no Nil, y con ello determinar si se trata de un objeto que ya fue destruido o no.
...
Pues creo que estamos muy cerca de dar con una solucion, aunque pienso que ésto ya debió pensarse cuando Delphi se estaba construyendo y que los creadores de Delphi ya debieron darle una solucion, o por lo menos tener alguna rutuna que la lo haga, pero que sea el programador quien decida si la usa o no.., en fin....si GetMem y FreeMem son reemplazable pues creo y viendo la situacion tenemos dos caminos posibles para una solucion(segun yo)
  1. Tener alguna rutina que cuando se libera un determinado Objeto con FreeMen, su referencia apunte a null;está solucion sería la primera que se estaba discutiendo y sería tener una rutina muy similar al FreeMem, es más podriamos escribir nuestra propia version de FreeMen, mas o menos de la siguiente Forma:
    Código Delphi [-]
    procedure MyFreeMem(var P: Pointer[; Size: Integer]);
    begin
       FreeMem(P);//aqui llamamos a nuestra la funcion normal
       P:=nil;//hacermos que P sea Nulo  ésta linea podría ser nuestra solucion
    end;
    Lógicamente tendriamos que hacer que se ejecute nuestra "nueva" version de FreeMem en código fuente de Delphi.
  2. Implementar algun mecanismo(rutina) que permita saber si una referencia apunta a un objeto destruido o no; lo cual viendolo más a fondo me parece que sería más engorroso, pero no imposible dado tu ejemplo que propones en el anterior post.
La cuestion es que de una u otra forma se solucione...
Como podrás ver, si se puede lograr la primera opcion creo que ya la cosa se soluciona...ALELUYA.. ¿verdad? o como lo vés tú amigo Alberto, ya que tú tienes mas experiencia que yo, pues eres un tremendo bibliotecarioy yo solo soy un simple aprendís
Saludos...
__________________
"Pedid, y se os dará; buscad, y hallaréis; llamad, y se os abrirá." Mt.7:7
Responder Con Cita
  #46  
Antiguo 30-01-2012
Avatar de rastafarey
rastafarey rastafarey is offline
Miembro
 
Registrado: nov 2003
Posts: 927
Poder: 21
rastafarey Va por buen camino
Resp

No se cuando tiempo tienen este hilo.

Este es el codigo de freeAndNil
Código Delphi [-]
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

Primero Nil
Y Luego Free.

Parece ilogico. pero no hay perdida de memoria.
__________________
Todo se puede, que no exista la tecnología aun, es otra cosa.
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
Forms: FreeAndNil ó Release y la validación Assigned? jbautista Varios 13 09-02-2010 17:33:03
Assigned y Free gluglu Varios 4 14-05-2007 21:03:37
Problemas FreeAndNil OscarG OOP 4 09-11-2005 12:48:46
Free Pascal 2.0 marcoszorrilla Noticias 6 19-05-2005 12:04:51
Componente free... Mauro® Varios 10 12-06-2004 13:15:24


La franja horaria es GMT +2. Ahora son las 05:29:15.


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