Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 25-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
FreeAndNil no libera los recursos

Hola, tengo el siguiente problema, Tengo la clase TConexionBD que es descendiente de un TDSServerModule, que creo vía código, realizando la siguiente llamada:
Código Delphi [-]
FConexionBD:=TConexionBD.Create(FProviderDataBD);{Creamos conexion con la BD}
Donde FProviderDataBD, es una clase que contiene los parámetros de conexión de la BD (Nombre base de datos, login, password, ruta BD, etc). El constructor de TConexionBD es el siguiente:
Código Delphi [-]
constructor TConexionBD.Create(AProvider:TProviderData);
begin
  inherited create(nil);{creamos el objeto}
  FManagerConexion:=TFDManager.Create(nil);{creamos manejador de conexion}
  FConexion:=TFDConnection.Create(nil);{Creamos contenedor de conexion}
  FConexion.LoginPrompt:= False;{Desactivamos el Prompt}
  FTransaction:=TFDTransaction.Create(nil);{Creamos manejador de transaciones}
  FConexion.Transaction:=FTransaction;{Asignamos la transacion}

  FParams:=TStringList.Create;{Creamos el contenedor de parametros de conexion}
  setParam(AProvider);{Creamos los parametros de conexion de acuerdo al proveedor de datos}
  setConexion(AProvider);{Establecemos definicion de la conexion de acuerdo al proveedor de datos}
end;{constructor}
Y el destructor de TConexionBD es el que sigue:
Código Delphi [-]
procedure TConexionBD.DSServerModuleDestroy(Sender: TObject);
begin
  Disconect;{Desconectamos la conexion con la BD}
  funGlobal.CloseObjet([FParams,FDPhysFBDriverLink,FTransaction,FConexion,FManagerConexion]);
end;{procedure}
Destructor que es llamado de la siguiente forma:
Código Delphi [-]
procedure TSystemClass.DestroyConexionBD;
begin
  funGlobal.CloseObjet([FConexionBD]);{cerramos los objetos}
end;{procedure}

procedure TfunGlobal.CloseObjet(AObjeto:Array of TObject);
var vIndice:Integer;
begin
  for vIndice:= Low(AObjeto) to High(AObjeto) do begin
    if Assigned(AObjeto[vIndice]) then FreeAndNil(AObjeto[vIndice]);{Liberamos la memoria}
  end;
end;{procedure}
Como verán la destrucción la llevo a cavo utilizando el método freeandnil y validando con assigned que el objeto halla sido creado con anterioridad. Es de suponer que al destruir el objeto este quedara en nil, pero no es así. Si llamo a DestroyConexionBD dos veces en la segunda llamada dispara un error de violación de acceso, esto no debería pasar ya que Assigned comprueba que el objeto este creado para destruirlo.
Preguntaran porque llamo 2 veces al destructor. El objeto se crea en forma manual por el usuario y también lo puede destruir el mismo usuario, pero los procedimientos al estar contenidos en un form la destrucción también se lleva a cavo al cerrar el form. Es decir, puede ocurrir que el usuario cierre el objeto y después al cerrar el form el cierre ocurre nuevamente. ¿Es correcta la forma de ?destruir el objeto?, ¿Assigned, comprueba realmente que el objeto ha sido creado?...

Saludos....
Responder Con Cita
  #2  
Antiguo 26-04-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 doctorhd.
Cita:
... ,¿Assigned, comprueba realmente que el objeto ha sido creado?...
No, la función Assigned comprueba si un puntero o una variable procedimental está o no asignada. Dicho de otro modo, la función Assigned devuelve True si el argumento es diferente de nil o False si es igual.

Pero una clase puede no haber sido instanciada (o ya liberada) y su valor ser diferente de nil, como puede verificarse en este ejemplo:
Código Delphi [-]
...
const
  MSG: array[Boolean] of string = ( 'DESASIGNADO', 'ASIGNADO' );
var
  o : TObject;
begin
  ShowMessage( MSG[Assigned(o)] ); // muestra ASIGNADO

  //------------------
  o := TObject.Create;
  o.Free;
  ShowMessage( MSG[Assigned(o)] ); // muestra ASIGNADO
  
  //-----------------
  o := TObject.Create;
  o.Free;   // | igual a:
  o := nil; // | FreeAndNil(o);
  ShowMessage( MSG[Assigned(o)] ); // muestra DESASIGNADO

Saludos
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #3  
Antiguo 27-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
ecfisa, entonces de que forma puedo validar que un objeto a sido liberado. Pensé que freeandnil, liberaba los recursos y establecía su valor a nil, por lo cual assigned debería devolver false....

Saludos
Responder Con Cita
  #4  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...Pensé que FreeAndNil, liberaba los recursos y establecía su valor a nil...


Es exactamente lo que hace FreAndNil y es lo que se demuestra en el código del Msg #2.

Revisa esta información:



Espero sea útil

Nelson.
Responder Con Cita
  #5  
Antiguo 27-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
nlsgarcia, entonces porque si al aplicar freandnil en mi código no establece el valor del objeto nil...
Saludos
Responder Con Cita
  #6  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...porque si al aplicar FreeAndNil en mi código no establece el valor del objeto nil...


Te sugiero hacer un debug al código en cuestión para verificar, cuando se aplica el FreeAndNil y cuando se verifica con Assigned la existencia del objecto.

Solo a modo de pruebas puedes aplicar un FreeAndNil al objeto en cuestión justo antes de comprobar el mismo con Assigned y veras lo comentado en los Msg #2 y #4

Espero sea útil

Nelson.
Responder Con Cita
  #7  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...porque si al aplicar FreeAndNil en mi código no establece el valor del objeto nil...


El problema radica en que estas pasando los objetos por valor y no por referencia al método TfunGlobal.CloseObjet.

Revisa este código
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TNelson = class
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure CloseNelson(var Nelson : Array of TNelson);
var
   i : Integer;
begin
   for i:= Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         FreeAndNil(Nelson[i]);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
   Nelson : Array[0..1] of TNelson;
   i : Integer;

begin

   for i := Low(Nelson) to High(Nelson) do
      Nelson[i] := TNelson.Create;

   for i := Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         MessageDlg(Format('Instancia %d de la clase Nelson',[i]),mtInformation,[mbOK],0)
      else
         MessageDlg(Format('Elemento %d del arreglo de clase Nelson no instanciado',[i]),mtInformation,[mbOK],0);

   for i := Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         FreeAndNil(Nelson[i]);

   for i := Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         MessageDlg(Format('Instancia %d de la clase Nelson',[i]),mtInformation,[mbOK],0)
      else
         MessageDlg(Format('Elemento %d del arreglo de clase Nelson no instanciado',[i]),mtInformation,[mbOK],0);

end;

procedure TForm1.Button2Click(Sender: TObject);
var
   Nelson : Array[0..1] of TNelson;
   i : Integer;

begin

   for i := Low(Nelson) to High(Nelson) do
      Nelson[i] := TNelson.Create;

   for i := Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         MessageDlg(Format('Instancia %d de la clase Nelson',[i]),mtInformation,[mbOK],0)
      else
         MessageDlg(Format('Elemento %d del arreglo de clase Nelson no instanciado',[i]),mtInformation,[mbOK],0);

   CloseNelson(Nelson);

   for i := Low(Nelson) to High(Nelson) do
      if Assigned(Nelson[i]) then
         MessageDlg(Format('Instancia %d de la clase Nelson',[i]),mtInformation,[mbOK],0)
      else
         MessageDlg(Format('Elemento %d del arreglo de clase Nelson no instanciado',[i]),mtInformation,[mbOK],0);

end;

end.
En el código anterior en Delphi 7 sobre Windows 7 Professional x32, el método TForm1.Button1Click instancia y libera objetos de la clase TNelson directamente, pero en el método TForm1.Button2Click la liberación de los objetos de la clase TNelson se hace por medio del procedimiento CloseNelson al cual se le pasa por referencia un arreglo de objetos TNelson, si el paso fuera por valor solo se aplicaria nil a los objetos actuales del arreglo Nelson del procedimiento CloseNelson, no a los objetos originales del arreglo Nelson del método TForm1.Button2Click, sin embargo los objetos serían liberados dado que el paso por valor contiene la referencia a los mismos.

La solución es :
Código Delphi [-]
procedure TfunGlobal.CloseObjet(var AObjeto : Array of TObject);
var
   vIndice : Integer;
begin
  for vIndice := Low(AObjeto) to High(AObjeto) do
    if Assigned(AObjeto[vIndice]) then
       FreeAndNil(AObjeto[vIndice]);
end;
Espero sea útil

Nelson.

Última edición por nlsgarcia fecha: 27-04-2015 a las 08:04:30.
Responder Con Cita
  #8  
Antiguo 27-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
nlsgarcia, Creo que ya encontré el error, este esta en la función que utilizo para cerrar los objetos:
Código Delphi [-]
procedure TfunGlobal.CloseObjet(AObjeto:Array of TObject);
var vIndice:Integer;
begin
  for vIndice:= Low(AObjeto) to High(AObjeto) do begin
    if Assigned(AObjeto[vIndice]) then FreeAndNil(AObjeto[vIndice]){Liberamos la memoria}
  end;{for}
end;{procedure}
Al parecer ciertos objetos se pasan por valor y no por referencia, ya que dentro del procedure freeandnil hace su trabajo y libera la memoria y los deja en nil, pero al salir del procedure dichos cambios no tienen efecto. Es muy raro ya que hasta donde se los objetos o clases siempre se pasan por referencia. Quizás exista algún error en la declaración del array que contiene los objetos...

saludos...
Responder Con Cita
  #9  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...ya encontré el error, este esta en la función que utilizo para cerrar los objetos...Quizás exista algún error en la declaración del array que contiene los objetos...


Te sugiero revisar y probar todo lo comentado en el Msg #7.

Espero sea útil

Nelson.
Responder Con Cita
  #10  
Antiguo 27-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
nlsgarcia, no había visto tu mensaje anterior...Al parecer llegamos a la misma conclusión, pero ahora mi duda es, ¿no se supone que los objetos siempre se pasan por referencia, sin necesidad de utilizar var...?

Saludos y gracias por tu ayuda..
Responder Con Cita
  #11  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...¿no se supone que los objetos siempre se pasan por referencia, sin necesidad de utilizar var?...


Cita:
Empezado por Marco Cantu
...Los objetos Delphi, de hecho, son siempre transmitidos mediante valores, porque ellos mismos son referencias...

Tomado de : Procedimientos y funciones en Pascal
Espero sea útil

Nelson.
Responder Con Cita
  #12  
Antiguo 27-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
nlsgarcia, citando el mismo texto que me indicas...
Cita:
Empezado por Marco Cantu
...Los objetos Delphi, de hecho, son siempre transmitidos mediante valores, porque ellos mismos son referencias...

Tomado de : Procedimientos y funciones en Pascal
le sigue a continuacion lo siguiente:
Cita:
Empezado por Marco Cantu
...Por esta razón, transmitir un objeto por referencia tendría poco sentido (aparte de casos muy especiales), porque consistiría en transmitir una referencia a otra.
Tomado de : Procedimientos y funciones en Pascal
Entonces, mi pregunta inicial:
Cita:
...¿no se supone que los objetos siempre se pasan por referencia, sin necesidad de utilizar var?...
sigue en pie...

Saludos
Responder Con Cita
  #13  
Antiguo 27-04-2015
Avatar de nlsgarcia
[nlsgarcia] nlsgarcia is offline
Miembro Premium
 
Registrado: feb 2007
Ubicación: Caracas, Venezuela
Posts: 2.206
Poder: 21
nlsgarcia Tiene un aura espectacularnlsgarcia Tiene un aura espectacular
doctorhd,

Cita:
Empezado por doctorhd
...mi pregunta inicial : ¿no se supone que los objetos siempre se pasan por referencia, sin necesidad de utilizar var?, sigue en pie...


Cita:
Empezado por Marco Cantu
...Los objetos Delphi, de hecho, son siempre transmitidos mediante valores, porque ellos mismos son referencias. Por esta razón, transmitir un objeto por referencia tendría poco sentido (aparte de casos muy especiales)...

Tomado de : Procedimientos y funciones en Pascal
Al pasar un objeto por valor se pasa una referencia al mismo, pero al aplicar el procedimiento FreeAndNil se libera el objeto pasado por valor y se asigna nil a la copia por valor de la variable del objeto en el procedimiento y/o función de llamada, no en la variable original del objeto, luego al verificar con Assigned el valor del objeto en el procedimiento y/o función original este es diferente de nil, es por esto que este caso es un caso especial.

Espero sea útil

Nelson.
Responder Con Cita
  #14  
Antiguo 27-04-2015
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
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
doctorhd:

Una cosa es un puntero a la instancia (referencia de objeto) y otra un puntero a una variable puntero a la instancia (referencia de variable objeto). Cuando el parámetro es "Var", estás pasando éste último. De lo contrario estás pasando el primero, copiándose ese puntero en el parámetro, el cual actúa como una simple variable objeto local. Si lo pones en Nil, sólo esa "variable" adquiere el valor de Nil; las demás variables (exteriores) que apunten a la misma instancia de objeto seguirán igual.

Espero no haberte confundido.

Saludos.
Responder Con Cita
  #15  
Antiguo 28-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
Gracias nlsgarcia y Al González por sus respuestas, me queda claro el origen del error.
Ahora a raíz del cambio indicado por ustedes, tengo el siguiente problema...(no se si sera necesario abrir un nuevo hilo)
al llamar a la función:
Código Delphi [-]
....
funGlobal.CloseObjet([FDetail]);{Destruimos las clases integrantes}
....

procedure TfunGlobal.CloseObjet(var AObjeto:Array of TObject);
var vIndice:Integer;
begin
  for vIndice:= Low(AObjeto) to High(AObjeto) do begin
    if Assigned(AObjeto[vIndice]) then FreeAndNil(AObjeto[vIndice]){Liberamos la memoria}
  end;{for}
end;{procedure}
tengo el siguiente error:
Código Delphi [-]
[dcc32 Error] ControlErroresUnit.pas(108): E2197 Constant object cannot be passed as var parameter
el cual indica que no puedo pasar una constante como parámetro a una función que requiere una variable, cuestión que no es cierta, ya que FDetail es un campo de una clase que a su vez también es una clase, aquí va la definición de ambas:

Código Delphi [-]
type
   TClassError = class
   private { Private declarations }
     FAccionOrigen:String;
     FTraceError:String;
     FMensajeError:String;
     FViewTraceError:Boolean;
     FTileMsg:string;
   public { Public declarations }
     constructor Create(AAccionOrigen:String;ATraceError:String;ATileMsg:String);
     procedure DisplayError;
     procedure SetMensajeError(AMensajeError:String);
     procedure SetViewTraceError(AViewTraceError:Boolean);
   public
     property AccionOrigen: String read FAccionOrigen;
     property TraceError: String read FTraceError;
     property MensajeError: String read FMensajeError;
     property ViewTraceError: Boolean read FViewTraceError;
   end;

type
   TControlErrores = class
   private { Private declarations }
     FDetail:TClassError;
     FTileMsg:string;
     procedure CreateMsgError(AError: Exception; AAccionOrigen:String; ATraceError:String);
     function ConstruyeMsgErroresDataSnap(AError:Exception; AAccionError:String; var AmsgSalida:String): Boolean;
     function ConstruyeMsgErroresBD(AError:Exception; AAccionError:String; var AmsgSalida:String): Boolean;
     function ConstruyeMsgErroresSistema(AError:Exception; AAccionError:String; var AmsgSalida:String): Boolean;
   public { Public declarations }
     constructor Create(AE:Exception;AAccionOrigen:String;ATileMsg:string);
     destructor Destroy; override;
     procedure DisplayError;
   public
      property Detail:TClassError read FDetail;
   end;

Saludos...
Responder Con Cita
  #16  
Antiguo 28-04-2015
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: may 2003
Posts: 5.604
Poder: 29
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
Podemos convenir que FDetail es una variable, concretamente un campo de una clase debidamente instanciada. Eso está bien, pero el "[FDetail]" que vemos en tu código es lo que formalmente se denomina un constructor de matriz abierta (open array constructor).

Ese término no se refiere a un método constructor, sino a una construcción gramatical que lleva corchetes con el propósito de formar una matriz "al vuelo". Al formarse esa matriz (array), cada uno de los elementos que contiene son considerados por el compilador como valores constantes (los punteros, no las instancias a las que apuntan). Por ello es que aparece el error que te da el compilador.

Si lo que necesitas es crear una rutina que reciba una matriz abierta de "variables" objeto, piensa en esa matriz o vector como una lista de punteros. Cada puntero señalando a una variable objeto. Para intentar ilustrarlo, tomo la función ghFreeNil de GH Freebrary que realiza una tarea similar (por ser el ejemplo más cercano que tengo).
Código Delphi [-]
  Type
    PObject = ^TObject;
  ...
  Procedure ghFreeNil (Const Objs :Array Of PObject);
  Var
    Obj :PObject;
  Begin
    For Obj In Objs Do  // Esta sintaxis de For es relativamente nueva en el compilador
      FreeAndNil (Obj^);
  End;
  ...
  // Llamamos a ghFreeNil dándole una matriz creada al vuelo (array de punteros a variables objeto)
  ghFreeNil ([@MiVariableObjeto1, @MiVariableObjeto2, @MiVariableObjeto3]);
¿Agarras la onda?
Responder Con Cita
  #17  
Antiguo 28-04-2015
doctorhd doctorhd is offline
Miembro
NULL
 
Registrado: abr 2013
Posts: 48
Poder: 0
doctorhd Va por buen camino
Gracias Al González. Y por supuesto Agarro la onda...
Saludos...
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

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
FreeAndNil VS Free GerTorresM OOP 45 30-01-2012 01:54:24
Forms: FreeAndNil ó Release y la validación Assigned? jbautista Varios 13 09-02-2010 17:33:03
Microsoft libera ASP .NET MVC AzidRain Noticias 3 10-04-2009 19:06:52
Problemas FreeAndNil OscarG OOP 4 09-11-2005 12:48:46
No libera la MEMORIA pruz Varios 1 27-04-2004 21:30:33


La franja horaria es GMT +2. Ahora son las 14:01:06.


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