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 05-10-2005
OscarG OscarG is offline
Miembro
 
Registrado: sep 2005
Posts: 35
Poder: 0
OscarG Va por buen camino
liberar objetos

Bueno, por mi parte como programador de seudo videojuegos (no hago quakes ni na parecido jeje) uno de mis miedos el liberar la memoria, ya sea de punteros y objetos...

Algunas cosas he leido sobre cómo liberar los objetos pero a veces tengo problemas q no encuentro solución.

Un ejemplo era con la clase TServerSocket q lo utilicé hace tiempo para un juego en red.

El problema era q a la hora de liberar dicho objeto, me daba error, no me dejaba hacer un .Free por lo q opté por la decisión de no liberarlo.

Supongo q si aprendo a liberar un TServerSocket, con otros problemas q me tope, tendré más oportunidades de solucionarlo.

En todo caso por lo q sé...todo objeto se libera con Free y yo lo suelo poner luego a nil porsiaca...
Responder Con Cita
  #2  
Antiguo 05-10-2005
Avatar de Neftali [Germán.Estévez]
Neftali [Germán.Estévez] Neftali [Germán.Estévez] is offline
[becario]
 
Registrado: jul 2004
Ubicación: Barcelona - España
Posts: 18.275
Poder: 10
Neftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en brutoNeftali [Germán.Estévez] Es un diamante en bruto
Cita:
Empezado por OscarG
...todo objeto se libera con Free y yo lo suelo poner luego a nil porsiaca...
Para eso te puede ser últi el procedimiento FreeAndNil (SysUtils en D6).
Creo que es obvio lo que hace...
__________________
Germán Estévez => Web/Blog
Guía de estilo, Guía alternativa
Utiliza TAG's en tus mensajes.
Contactar con el Clubdelphi

P.D: Más tiempo dedicado a la pregunta=Mejores respuestas.
Responder Con Cita
  #3  
Antiguo 05-10-2005
lento manu lento manu is offline
Miembro
 
Registrado: oct 2004
Posts: 29
Poder: 0
lento manu Va por buen camino
Ejecutar o indultar

Por lo que voy entendiendo, creo que solo hay que liberar los objetos que creamos espeficicamente. Quiero decir que si usamos objetos que hemos añadido al private o al public y no presisan de un TmiObjeto.create, por mi experiencia, creo que es mejor el indulto, pero todos los que has generado con algún .create deben pasar por las manos del verdugo.
Lo que no se es porque algunos objetos existen por si mismos y otros no, no se si es por su componente visual, o sea si debe ser pintado o no... ¿alguén los sabe? o ¿estoy metiendo la pata hasta el fondo?
Con respecto al
Código Delphi [-]
 if Assigned(miobjeto) 
    then FreeAndNil(miobjeto);
a veces me explota ya en if Assigned pq ya no existe. ¿Ilógico no?
Responder Con Cita
  #4  
Antiguo 05-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Cita:
Empezado por lento manu
Lo que no se es porque algunos objetos existen por si mismos y otros no, no se si es por su componente visual, o sea si debe ser pintado o no... ¿alguén los sabe? o ¿estoy metiendo la pata hasta el fondo?
Al crear un objeto Pepe:TObject tienes que especificar el dueño (parámetro AOwner), si le pones nil a ese parámetro, tienes que hacer un FreeAndNil(Pepe) obligatoriamente. Si en AOwner le das: Application, Form1, panel1, cuando se vaya a destruir ese objeto, él se encargará de liberar a Pepe.
Cita:
Empezado por lento manu
Con respecto al
Código Delphi [-]
 if Assigned(miobjeto) 
    then FreeAndNil(miobjeto);
a veces me explota ya en if Assigned pq ya no existe. ¿Ilógico no?
[/quote]
Si miobjeto está declarado dentro de Form1, y has liberado Form1, entonces si da el error.

Assigned solo comprueba que el valor de esa variable contiene el valor "nil" o bien una dirección de memoria. Recuerda que todos los objetos son, en realidad, punteros de memoria. Assigned solo comprueba el valor que tiene ese puntero. No el objeto en sí.

De hecho, cuando haces un Pepe.Free, el puntero Pepe no apunta a nil, se queda con basura y pueden venir Access violation al intentar acceder a pepe.

Saludando, dejo tranquilo a Pepe

Última edición por Lepe fecha: 05-10-2005 a las 20:19:51.
Responder Con Cita
  #5  
Antiguo 06-10-2005
OscarG OscarG is offline
Miembro
 
Registrado: sep 2005
Posts: 35
Poder: 0
OscarG Va por buen camino
Bueno, conozco el FreeAndNil, pero no lo suelo usar...manias...

Lo q quiero decir con crear, viendo lo comentado y según me acuerdo, (es un programa q hice hace 1 año) es q yo creaba un cliente y un servidor.

TServerSocket
TClientSocket

El procedimiento para cada uno era tener una clase por cada y dentro de ella declarar un servidor o un cliente y q esa clase le controle su comportamiento...

Entonces, a estos les pasaba al crearlos el TComponent del formulario.

Entonces al destruir la clase q contenía el TServerSocket no me dejaba hacer un FreeAndNil del objeto, en cambio, con el TClientSocket si me dejaba...

Creo recordar q me comí un poco la cabeza probando formas diferentes para q no cascase, pero al final opté por q lo libere la aplicación al destruirse, ya q dependía del formulario principal...

Este caso, me mosqueo, xq me parecía q hacia todo bien

Código Delphi [-]
SSocket:= TServerSocket.Create(AOwner);
 SSocket.Port := 9998;
 SSocket.Active := false;
 SSocket.ServerType:= stNonBlocking;
 SSocket.ThreadCacheSize:= 10;
 SSocket.OnClientRead := ServerSocketClientRead;
 SSocket.OnClientError := ServerSocketClientError;
 SSocket.OnClientConnect := ServerSocketClientConnect;
 SSocket.OnClientDisconnect:= ServerSocketClientDisconnect;
pero no me dejaba luego liberarlo, al hacerlo me salía un error.

Pos eso, muchas gracias...

Última edición por dec fecha: 06-10-2005 a las 13:20:30. Razón: ¡¡Encerrad el código fuente entre las etiquetas [DELPHI] ... [/DELPHI]!!
Responder Con Cita
  #6  
Antiguo 06-10-2005
OscarG OscarG is offline
Miembro
 
Registrado: sep 2005
Posts: 35
Poder: 0
OscarG Va por buen camino
Bueno, conozco el FreeAndNil, pero no lo suelo usar...manias...

Lo q quiero decir con crear, viendo lo comentado y según me acuerdo, (es un programa q hice hace 1 año) es q yo creaba un cliente y un servidor.

TServerSocket
TClientSocket

El procedimiento para cada uno era tener una clase por cada y dentro de ella declarar un servidor o un cliente y q esa clase le controle su comportamiento...

Entonces, a estos les pasaba al crearlos el TComponent del formulario.

Entonces al destruir la clase q contenía el TServerSocket no me dejaba hacer un FreeAndNil del objeto, en cambio, con el TClientSocket si me dejaba...

Creo recordar q me comí un poco la cabeza probando formas diferentes para q no cascase, pero al final opté por q lo libere la aplicación al destruirse, ya q dependía del formulario principal...

Este caso, me mosqueo, xq me parecía q hacia todo bien
Código Delphi [-]
  SSocket:= TServerSocket.Create(AOwner);
  SSocket.Port :=               9998;
  SSocket.Active :=             false;
  SSocket.ServerType:=          stNonBlocking;
  SSocket.ThreadCacheSize:=     10;
  SSocket.OnClientRead :=         ServerSocketClientRead;
  SSocket.OnClientError :=         ServerSocketClientError;
  SSocket.OnClientConnect :=    ServerSocketClientConnect;
  SSocket.OnClientDisconnect:=  ServerSocketClientDisconnect;

pero no me dejaba luego liberarlo, al hacerlo me salía un error.

Pos eso, muchas gracias...
Responder Con Cita
  #7  
Antiguo 06-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Explicación detallada:

Tu hacias un .Free del SSocket, se libera pero no queda apuntando a nil el valor de SSocket, por tanto, cuando el Aowner se destruye, accede a SSocket, ve que es distinto de nil, e intenta liberar una zona de memoria que ya ha sido liberada => Access Violation.

Si hubieras usado Freeandnil(SSocket), cuando el Aowner va a destruirlo con .Free, se detecta que SSocket es = nil, y por tanto, no se destruye, No hay Access Violation.

Moraleja: Haz un curso de autoControl y quitate la manía que tienes con FreeAndNil

Un saludo
Responder Con Cita
  #8  
Antiguo 06-10-2005
OscarG OscarG is offline
Miembro
 
Registrado: sep 2005
Posts: 35
Poder: 0
OscarG Va por buen camino
Que yo sepa, FreeAndNil es lo mismo q poner un objeto Free y luego igualarlo a nil. Ya se q son 2 pasos en vez de uno pero creo q són lo mismo.

Me parece extraño q no lo haya probado, más bien diría imposible, (no poner FreeAndNil, sino, ponerlos por separados, Free y luego nil...) en el ejemplo del TServerSocket.

Si evito poner FreeAndNil es xq en mis inicios me dio algunos problemas q resolví quitandolo...seguramente sería por ser novato y si algo me da problemas he aprendido a evitarlos y buscar otra forma de hacerlo.

Hoy pienso q sería por otra cosa pero aún asi, intento evitarlo porsiaca.

He cargado una prueba q tenía de cuanto investigé los TServerSocket, y le he puesto FreeAndNil y casca, al igual q poner Free y luego Nil...en la prueba lo he puesto en el FormDestroy, luego lo he probado con un botón para crear un ServerSocket y otro para eliminarlo y me ha funcionado...asi q debe ser por ponerlo en el FormDestroy.
¿Xq´ casca en el Destroy?
Ya q si tengo el método para eliminarlo en el Destroy pero anteriormente con el botón q creé para eliminar el Server lo pulso, entonces no casca (ya q en el destroy miro si está asignado), sólo casca si está creado el ServerSocket y lo libero en el Destroy...
Responder Con Cita
  #9  
Antiguo 06-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Código Delphi [-]
procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj);
  Pointer(Obj) := nil;
  Temp.Free;
end;

como ves se hace al revés ¿Por qué? Porque puede ocurrir alguna excepción al tiempo de liberar el objeto, y entonces no quedaría apuntando a nil, y el peligro sería el mismo.

En cuanto a lo demás, sería mejor que pegaras el código que te da error; ya que tengo mis dudas en eso de usar FormDestroy, ¿no querrás decir FormClose?

De hecho nunca se debe llamar a destroy, siempre se debe usar .Free sencillamente por esto:
Código Delphi [-]
procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Si primero se usa FreeAndnil, la siguiente llamada a .Free no causará daño alguno.

Si se usa FreeAndNil y despues .Destroy, seguro que casca porque Destroy no comprueba el valor de nil.

Un saludo

Un saludo
Responder Con Cita
  #10  
Antiguo 06-10-2005
adlfv adlfv is offline
Miembro
 
Registrado: may 2005
Posts: 39
Poder: 0
adlfv Va por buen camino
Unhappy

Hola a todos, yo creo que tengo el mismo error... y me estoy volviendo LOOOOCO y no logro resolverlo. Seguramente sea una tontería, pero es que NO LO LOGRO.

Explico mi caso.

Estoy haciendo el modelo de negocios de un hotel, el cual explico brevemente:
- Clase THabitaciones (hereda de TComponent), que es básicamente una lista con componentes THabitacion (o TBaseHabitacion).
- Clase THabitacion (hereda de TComponent), representa una habitación como tal. Está formada basicamente por dos partes, Un componente GUI: TBaseGUI y un objeto Info: TBaseInfo.
- Clase TBaseGUI (hereda de TComponent), es el tope de una jerarquia para la representación gráfica de las habitaciones.
- Clase TBaseInfo (hereda de TObject), es el tope de una jerarquia para la información de las habitaciones. Va variando según el tipo en tiempo de ejecución.


En el form principal hago lo siguiente en el evento OnClose:
Código:
 ...
 TiposHabitaciones.Free;
 Habitaciones.Free;

La idea es:
1.- Destruir Habitaciones: THabitaciones (cuando creo una Habitacion: THabitacion hereda de TComponent y el Owner es Habitaciones, con lo cual automáticamente se liberan todas las THabitacion cuyo Owner sea Habitaciones).
2.- Cuando se destruye una Habitacion: THabitacion, básicamente tengo que destruir la Info pues hereda de TBaseInfo que a su vez hereda de TObject. GUI no hay que destruirlo, pues se autodestruye porque tiene como Owner la Habitacion
3.- Cuando se destruye un GUI: TGUIHab, debo liberar el bitmap.


A continuación pondré los métodos de destrucción de las clases en ese orden:


1.- Destrucción de Habitaciones: (en realidad no hago nada salvo Lista.Clear y Lista.Free).

Código:
 Debug('THabitaciones.Destroy: ComponentCount:' + IntToStr(ComponentCount));
 Debug('THabitaciones.Destroy: FLista.Count:' + IntToStr(FLista.Count));
 
 for i := 0 to FLista.Count -1 do
 begin
   H := ItemsByPos[i];
   if Assigned(H) then
   begin
 	if H.Owner <> nil then
 	  Debug(H.Caption + ' Owned by: ' + TComponent(H.Owner).Name);
 //	H.FreeInfo;
 //	H.FreeGUI;
 //	H.Free;
   end;
 //  Lista.Objects[i].Free;
 end;
 
 Lista.Clear;
 Debug('THabitaciones.Destroy: ComponentCount:' + IntToStr(ComponentCount));
 
 Lista.Free;
 Debug('La lista interna ha sido liberada');
 inherited Destroy;

2.- Destrucción de Habitacion: Tengo qeu destruir sólo la Info (pero está comentado, pues sospecho que me da error en el Assigned(Info)) pues el GUI tiene como Owner la Habitación y se destruirá solo.


Código:
 Debug(Caption + ': THabitacion.Destroy: ComponentCount:' + IntToStr(ComponentCount));
 
 if Assigned(Info) then
 begin
   Debug(Caption + ': TBaseHab.Destroy - assignado. Tipo:' + Info.ClassName);
 //  FreeInfo;
 //  FreeGUI;
 end
 else
   Debug(Caption + ': TBaseHab.Destroy - no assignado');
 
 Debug(Caption + ': THabitacion.Destroy: ComponentCount:' + IntToStr(ComponentCount));
 inherited Destroy

3.- Destrucción de GUI.


Código:
 if Assigned(Owner) then
 begin
   Debug('Liberando bitmap de GUI de la habitacion: ' + TComponent(Owner).Name);
   FreeResources;
 end;
 
 Debug('TGUIHabIcon: ComponentCount=' + IntToStr(ComponentCount));
 
 //TODO: LLamar al heredado?

La destrucción de Info no hace nada salvo llamar al heredado.


Al cerrar la aplicación obtengo un precioso mensaje : "Invalid pointer operation." (EInvalidPointer)

Alguien me puede echar una mano con esto, por favor.

Le estaré muy agradecido, pues no logro detectar el error... Creo que falla en el if Assigned(Info) de THabitacion.Destroy, pero no estoy seguro y además no sé cómo resolverlo.

Muchas gracias de antemano y disculpen por el mensaje tan largo.

PD: A continuación adjunto la pila, por si pueda ser útil.

------------------------------------------------------------------------------------------------
|Address |Module |Unit |Class |Procedure/Method |Line|
------------------------------------------------------------------------------------------------
|40003364|rtl90.bpl |System.pas | |Error | |
|400031AB|rtl90.bpl |System.pas | |_FreeMem | |
|40003198|rtl90.bpl |System.pas | |_FreeMem | |
|40005DBE|rtl90.bpl |System.pas | |_ClassDestroy | |
|40005DBC|rtl90.bpl |System.pas | |_ClassDestroy | |
|01658F68|CoreClassHab.bpl|UCGUIHab.pas |TGUIIcon |Destroy |127 |
|4003D718|rtl90.bpl |Classes.pas |TComponent |DestroyComponents | |
|4003D518|rtl90.bpl |Classes.pas | |TComponent | |
|01654CD6|CoreClassHab.bpl|UCHabitaciones.pas|TBaseHabitacion|Destroy |195 |
|77D2F3DE|user32.dll | | |SendMessageA | |
|77D2F39A|user32.dll | | |SendMessageA | |
|0067455A|vcl90.bpl |Comctrls.pas |TCustomListView|Scroll | |
|40006B58|rtl90.bpl |System.pas | |_LStrArrayClr | |
|003F203E|CoreLog.bpl |ULog.pas | |Log |64 |
|4003D718|rtl90.bpl |Classes.pas |TComponent |DestroyComponents | |
|4003D518|rtl90.bpl |Classes.pas | |TComponent | |
|01655442|CoreClassHab.bpl|UCHabitaciones.pas|THabitaciones |Destroy |429 |
|400059D4|rtl90.bpl |System.pas |TObject |Free | |
|400059CC|rtl90.bpl |System.pas |TObject |Free | |
|01654433|CoreClassHab.bpl|UClassObjects.pas | |CoreClassHabDestroy |30 |
|01654424|CoreClassHab.bpl|UClassObjects.pas | |CoreClassHabDestroy |29 |
|01715794|CoreMain.bpl |UPrincipal.pas |TFrmPrincipal |FormClose |357 |

Responder Con Cita
  #11  
Antiguo 06-10-2005
lento manu lento manu is offline
Miembro
 
Registrado: oct 2004
Posts: 29
Poder: 0
lento manu Va por buen camino
gracias por las aclaraciones

Gracias por tus aclaraciones, Lepe. Pero es un tema difícil de seguir, ya que realmente el compilador explota, y cuesta mucho encontrar el punto donde sucede esta explosión. He tenido este problema en el componente que discutimos en el hilo Override eventos On... (http://www.clubdelphi.com/foros/showthread.php?t=25540)
Si en el destroy del objeto repaso si debo destruir el objeto creado con
Código Delphi [-]
destructor TDBexplorer.Destroy;
begin
  if Modal then
    begin
      //no destruir si no es modal: error de assigned
      if Assigned(Explorador) then
        FreeAndNil(Explorador);
   end;
  inherited Destroy;
end;
he concluido lo que describo en el comentario //... Lo que quiere decir que si el Tform creado esta generado como no Modal, se ha liberado automáticamente por si mismo, por lo menos su puntero ¿no?, pero si es Modal si pasa por el código y realiza el FreeAndNil(Explorador). Depurando es muy difícil de seguir esto, ya que se reciben los típicos avisos de Access Violation Address con matrículas que a los mortales no nos dicen nada, y cuesta encontrar en que línea de código sucede, ya que el compilador no la muestra por defecto. Para mi, creo que este es el gran defecto de Delphi, por lo menos su talón de Aquiles.Y entiendo la opción de descartar estas llamadas, por impotencia. Actualmente tengo estos errores al cerrar un proyecto, no se cierra adecuadamente y tengo Access Violation Address ...in module rtl60.dpl se cuelga Delphi simplemente por abrir y cerrar el proyecto, pero no por depurarlo ¿...? incluso el exe rueda OK y no produce errores. Por supuesto cuando sale la ventana de las direcciones de memoria del compilador, para mi es peor que el chino, árabe y japonés todo junto. Si tenéis alguna pista, ...gracias a todos.
Responder Con Cita
  #12  
Antiguo 06-10-2005
OscarG OscarG is offline
Miembro
 
Registrado: sep 2005
Posts: 35
Poder: 0
OscarG Va por buen camino
Me he quedado de piedra...
Si q tienes razón q tiene q ser en el close...el caso es q lo he puesto en el FormClose y parece q ya no casca...menudo despiste . Aún asi investigaré en la aplicación q me daba el problema... xq esto era un ejemplo y en una aplicación, me corto las venas si veo q pongo algo en el Destroy..., si encuentro algo raro lo comentaré en este hilo.

Por lo otro lado, también admito mi error en lo de FreeAndNil, a partir de ahora le tendré más respeto a dicho método.

Bueno, hoy por lo menos he aprendido cosas...

Otra preguntita q me ha salido hoy sobre liberar...


Estoy con un componente de música q me he bajado, el ACS
Audio Components Suite
para ulilizar oggs, la cosa es q quiero cerrar el sonido y liberarlo y me da un error...

esto lo hago con 2 botones, uno para crear el objeto y otro para liberarlo.
En la ayuda encontré q antes de liberar el objeto había q parar la música si estaba sonando, cosa q hice y sigue fallando.

Supongo q no conoceis el componente, pero igual teneis esperiencia con música, yo por lo q veo, no le doy tiempo a q se cierre y por eso falla, ya q si pongo en un botón, parar la música y en otro liberarlo y no los pulso muy rápido, pos no salen problemas...

He pensado en poner un sleep, pero no me gusta, aunq igual es la única solución q me queda...aunq igual hay algún método q te diga si el objeto está lista para ser liberado...


Pos nada, gracias por las contestaciones y por las molestias...
Responder Con Cita
  #13  
Antiguo 06-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
adlfv: FLista ¿de qué tipo es? Tiene toda la pinta de Tobjectlist o similar, y se puede destruir de otra forma más simple.

Obviamente los errores vienen aqui:
|01654424|CoreClassHab.bpl|UClassObjects.pas | |CoreClassHabDestroy |29 y 30
|01655442|CoreClassHab.bpl|UCHabitaciones.pas|THabitaciones |Destroy |429 |
|01654CD6|CoreClassHab.bpl|UCHabitaciones.pas|TBaseHabitacion|Destroy |195 |
|01658F68|CoreClassHab.bpl|UCGUIHab.pas |TGUIIcon |Destroy |127 |

En cuanto a la filosofia, lo veo muy complejo, "este ahora si lo tengo que liberar", "este otro no"... unifica criterios y objetos, los que tengan que liberarse a mano en un sitio y los demás a otro sitio.

Y siempre usa Freeandnil, ya que unos hacen referencias a otros.

lento manu:
Para el tema del número de linea revisa este hilo reciente

Saludos
Responder Con Cita
  #14  
Antiguo 06-10-2005
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
¡¡ME VA A DAR UN INFARTO CEREBRAL !!

Ya he perdido la cuenta de cuantos temas se llevan en este hilo al mismo
tiempo. ¡¡¡ Por mi salud !!!, abrid un hilo distinto para
cada nueva pregunta que vaya saliendo
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


La franja horaria es GMT +2. Ahora son las 07:59:16.


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