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 12-11-2008
elcigarra elcigarra is offline
Miembro
 
Registrado: may 2005
Posts: 269
Poder: 19
elcigarra Va por buen camino
más buenas prácticas de programación

Una consulta relacionada a otro hilo que comencé con este nombre, y referente a la liberación de la memoria. Alguien me puede explicar por qué no se puede hacer lo siguiente:
Código Delphi [-]
function TForm1.GetStrings:TStrings;
var
  miLista: TStrings;
begin
  miLista := TStringList.Create;
  miLista.Add('uno');
  miLista.Add('dos');
  Result := miLista;
  FreeAndNil(MiLista); // Esta linea da un error EAccessViolation
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
  memo1.Lines.Assign(GetStrings);
end;

Y sabiendo que no puede hacerse esto, como entonces puedo liberar la memoria de la variable miLista creada en esa función.
Responder Con Cita
  #2  
Antiguo 12-11-2008
Avatar de donald shimoda
donald shimoda donald shimoda is offline
Miembro
 
Registrado: jul 2008
Ubicación: Argentino en Santa Cruz de la Sierra
Posts: 1.083
Poder: 17
donald shimoda Va por buen camino
Cita:
Empezado por elcigarra Ver Mensaje
Y sabiendo que no puede hacerse esto, como entonces puedo liberar la memoria de la variable miLista creada en esa función.
Estas intentando devolver un objeto que destruyes en la linea posterior.

Opciones hay muchas,y no entiendo bien que queres hacer, pero como sea que lo hagas deberías destruir el objeto solo después de usarlo, es decir en el código que lo recibe. Ejemplo tosco:

Código Delphi [-]
procedure TForm1.GetStrings(var MyStrings:TStrings);
begin
  MyStrings.Clear;
  MyStrings.Add('uno');
  MyStrings.Add('dos');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  miLista: TStrings;
begin
  miLista := TStringList.Create;
  GetStrings(miLista)
  memo1.Lines.Assign(miLista);
  FreeAndNil(MiLista); 
end;

Saludos
__________________
Donald Shimoda [Team RO] - Blogs: Remobjects Pascal
Responder Con Cita
  #3  
Antiguo 12-11-2008
Avatar de Caro
*Caro* Caro is offline
Moderadora
 
Registrado: jul 2004
Ubicación: Cochabamba, Bolivia
Posts: 2.544
Poder: 22
Caro Va por buen camino
Cita:
Empezado por donald shimoda Ver Mensaje
Estas intentando devolver un objeto que destruyes en la linea posterior.
Estoy de acuerdo con el amiguito Donald .

También podrías no crearte el TStrings y mandarle directo a tu función Memo.Lines que ya es un TStrings. Tu codigo quedaría así:

Código Delphi [-]
procedure TForm1.GetStrings(miLista : TStrings);
begin
  miLista.Add('uno');
  miLista.Add('dos');
end;
 
procedure TForm1.Button1Click(Sender: TObject);
begin
 GetStrings(Memo1.Lines);
end;

Saluditos
__________________
Disfruten cada minuto de su vida a lado de sus seres queridos como si fuese el ultimo, uno nunca sabe lo que puede pasar.
Responder Con Cita
  #4  
Antiguo 12-11-2008
Avatar de ElKurgan
[ElKurgan] ElKurgan is offline
Miembro Premium
 
Registrado: nov 2005
Posts: 1.232
Poder: 20
ElKurgan Va camino a la fama
También te queda otra opción, como es el devolver los datos directamente como tipos de datos simples, puros y duros:

Código Delphi [-]
function TForm1.GetStrings:String;
var
  miLista: TStrings;
begin
  miLista := TStringList.Create;
  try  miLista.Add('uno');
    miLista.Add('dos');
    Result := miLista.Text;
  finally
    FreeAndNil(MiLista);
  end
end;
  
procedure TForm1.Button1Click(Sender: TObject);
begin 
  memo1.Lines.Text := GetStrings;
end;

Un saludo

Última edición por roman fecha: 12-11-2008 a las 19:28:29. Razón: Corregir formato de código
Responder Con Cita
  #5  
Antiguo 12-11-2008
Avatar de ElKurgan
[ElKurgan] ElKurgan is offline
Miembro Premium
 
Registrado: nov 2005
Posts: 1.232
Poder: 20
ElKurgan Va camino a la fama
ARGH... Pero... ¿Que le pasa a mi editor?

Mil perdones
Responder Con Cita
  #6  
Antiguo 12-11-2008
Avatar de DarkMan
DarkMan DarkMan is offline
Miembro
 
Registrado: jul 2006
Posts: 102
Poder: 18
DarkMan Va por buen camino
TStringList es una clase TObject, la variable no contiene la clase en sí, sino su referencia. Esto quiere decir que es un puntero a la dirección de memoria en la que se contiene ese objeto.

En esa función lo que haces es devolver el puntero a una dirección de memoria que contiene el objeto que tu has destruido en la misma función, por ello te salta el error. En todo caso, si deseas seguir con esa sintaxis debería ser así el código:
Código Delphi [-]
function TForm1.GetStrings:TStrings;
var
  miLista: TStrings;
begin
  miLista := TStringList.Create;
  miLista.Add('uno');
  miLista.Add('dos');
  Result := miLista;
{  FreeAndNil(MiLista); // Esta linea da un error EAccessViolation}
end;
procedure TForm1.Button1Click(Sender: TObject);
var MiLista: TStrings;
begin
 MiLista:= GetStrings;  
 memo1.Lines.Assign(MiLista);
 FreeAndNil(MiLista);
 {Ahora ya has liberado el objeto creado en la función anterior}
end;
__________________
"La recompensa de una buena acción está en haberla hecho"
Responder Con Cita
  #7  
Antiguo 12-11-2008
Avatar de ContraVeneno
ContraVeneno ContraVeneno is offline
Miembro
 
Registrado: may 2005
Ubicación: Torreón, México
Posts: 4.738
Poder: 23
ContraVeneno Va por buen camino
¿por qué no seguir el ejemplo que viene en la ayuda de delphi?
Es decir, en el ejemplo de la ayuda de delphi, la última línea dice:
MyList.Free
no utilizan FreeAndNil....
Así que esto no debería darte problemas:
Código Delphi [-]
...
 miLista := TStringList.Create; 
 miLista.Add('uno'); 
 miLista.Add('dos'); 
 Result := miLista;   
 MiLista.Free; 
...

Aunque me gusta más lo que propone Caro, digo, si ya tienes un stringlist, ¿para qué crear otro?
__________________

Responder Con Cita
  #8  
Antiguo 12-11-2008
Avatar de donald shimoda
donald shimoda donald shimoda is offline
Miembro
 
Registrado: jul 2008
Ubicación: Argentino en Santa Cruz de la Sierra
Posts: 1.083
Poder: 17
donald shimoda Va por buen camino
Cita:
Empezado por ContraVeneno Ver Mensaje

Así que esto no debería darte problemas:
Código Delphi [-]
...
 miLista := TStringList.Create; 
 miLista.Add('uno'); 
 miLista.Add('dos'); 
 Result := miLista;   
 MiLista.Free; 
...
Amigo, repites el error del pimer post. Freeandnil solo hace

Código Delphi [-]
if Assigned(x) then
  x.free;
Es decir valida que solo libera cuando esta creado. Es codigo seguro.

Lo que tu colocas da problemas porque sigues liberando un objeto que pretendes devolver.

Saludos.
__________________
Donald Shimoda [Team RO] - Blogs: Remobjects Pascal
Responder Con Cita
  #9  
Antiguo 12-11-2008
Avatar de donald shimoda
donald shimoda donald shimoda is offline
Miembro
 
Registrado: jul 2008
Ubicación: Argentino en Santa Cruz de la Sierra
Posts: 1.083
Poder: 17
donald shimoda Va por buen camino
Cita:
Empezado por DarkMan Ver Mensaje
{Ahora ya has liberado el objeto creado en la función anterior}
El problema de esto es que no tiene sentido crear un objeto en una función y liberarlo en otra. Por que? Porque en este caso una función es totalmente dependiente de la otra. Entonces para que separarlas?

Saludos.
__________________
Donald Shimoda [Team RO] - Blogs: Remobjects Pascal
Responder Con Cita
  #10  
Antiguo 12-11-2008
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Desde mi punto de vista, no es buena idea que una rutina interna cree un objeto y que después sea el usuario del módulo el que deba destruirlo. Si ha de hacerse así, hay que documentarlo muy bien.

Lo que yo haría:
Código Delphi [-]
function TForm1.SetStringsTo(var milista:TStrings);
begin
  if not Assigned(milista) then
     raise Exception.Create('proc TForm1.GetStrings:Se necesita una lista  creada');
  miLista.Add('uno');
  miLista.Add('dos');
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SetStringsTo(memo1.lines);  
end;

Hay que guardar la semántica en delphi, dicho de otra forma, si veo este código dentro de 1 año:
Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var MiLista: TStrings;
begin
 MiLista:= GetStrings;  
 memo1.Lines.Assign(MiLista);
 FreeAndNil(MiLista);
 {Ahora ya has liberado el objeto creado en la función anterior}
end;
Lo primero que digo es: " MiLista no ha sido creado", ahora tengo que buscar la implementación de GetStrings y ver si dentro se llama a Milista.Create.

Lo correcto según mi opinión es:

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
var MiLista: TStrings;
begin
 MiLista:= TStringList.Create;
 GetStrings(Milista);
 FreeAndNil(MiLista);
end;
dentro de esa rutina queda claro que has creado un TStringList y lo estás liberando, no hay dudas. Ten en cuenta que TStrings es una clase con descendientes, por tanto milista puede ser un TstringList, TMemoStrings, TComboboxStrings, etc., todos ellos son compatibles porque heredan de TStrings, pero no son iguales. En ese código, dejas claro que se trata de un TStringList.

Por cierto, el nombre de la rutina, "GetStrings", me parece ambiguo, (ya sé que es sólo un ejemplo, pero en fin, a ver si me explico...) si dentro de GetStrings estoy añadiendo elementos a la variable "MiLista" yo le cambiaría el nombre, por algo así como "AddItemsTo(Milista)".

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #11  
Antiguo 12-11-2008
Avatar de Caro
*Caro* Caro is offline
Moderadora
 
Registrado: jul 2004
Ubicación: Cochabamba, Bolivia
Posts: 2.544
Poder: 22
Caro Va por buen camino
Cita:
Empezado por ContraVeneno Ver Mensaje
¿por qué no seguir el ejemplo que viene en la ayuda de delphi?
Es decir, en el ejemplo de la ayuda de delphi, la última línea dice:
MyList.Free
Te daría el mismo error amiguito, ya que se estaría liberando antes de hacerle el Assign a la Lines del Memo.

Por lo menos yo cuando libero un TStringList lo hago con FreeAndNil, porque, digamos que tengo un tStringList como variable global en mi Unit. Cuando libero con Free y en otro lugar hago esto:

Código Delphi [-]
 if Assigned(Lista) then
  //Si existe quiero obtener su contenido

Al no haberlo hecho con FreeAndNil habiendolo liberado antes me sale un accessViolation, por eso lo libero con FreeAndNil.

Saluditos
__________________
Disfruten cada minuto de su vida a lado de sus seres queridos como si fuese el ultimo, uno nunca sabe lo que puede pasar.
Responder Con Cita
  #12  
Antiguo 12-11-2008
Avatar de ContraVeneno
ContraVeneno ContraVeneno is offline
Miembro
 
Registrado: may 2005
Ubicación: Torreón, México
Posts: 4.738
Poder: 23
ContraVeneno Va por buen camino
ya, me guíe por el ejemplo de Delphi, no me había fijado que era una función que tendría que regresar ese valor.
__________________

Responder Con Cita
  #13  
Antiguo 12-11-2008
Avatar de Lepe
[Lepe] Lepe is offline
Miembro Premium
 
Registrado: may 2003
Posts: 7.424
Poder: 28
Lepe Va por buen camino
Resumiendo:
Si vas a reutilizar una variable varias veces (crearla en memoria y liberarla) es mejor usar FreeAndNil.

Si sólo vas a crear y destruir la variable una vez, puedes usar variable.Free;

Saludos
__________________
Si usted entendió mi comentario, contácteme y gustosamente,
se lo volveré a explicar hasta que no lo entienda, Gracias.
Responder Con Cita
  #14  
Antiguo 12-11-2008
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
¡Hola!

Cita:
Empezado por donald shimoda Ver Mensaje
...Freeandnil solo hace

Código Delphi [-]
if Assigned(x) then
  x.free;
Es decir valida que solo libera cuando esta creado. Es codigo seguro...
Disculpa que te corrija Donald, pero eso no es lo que hace FreeAndNil. Linett ha dado una explicación más cierta; la variable objeto queda con un valor en blanco (Nil) tras su liberación con FreeAndNil. Es el propio método Free el que hace una validación de seguridad antes de llamar al destructor Destroy.

Como ya se dijo, es normal utilizar FreeAndNil con variables globales, y aunque también puede ser aplicado a variables locales, por lo general sólo utilizamos Free con éstas. En otras palabras, el uso de FreeAndNil se justifica cuando existe la posibilidad de que alguna parte del código intente hacer algo con la instancia de objeto apuntada por la variable después de haberse destruido dicha instancia.

Por otro lado, la solución propuesta por Linett al principio me parece la más adecuada. Cuando mucho haría falta una llamada al método Clear antes del primer Add.

Un abrazo sin destruir.

Al González.

Última edición por Al González fecha: 12-11-2008 a las 18:51:17.
Responder Con Cita
  #15  
Antiguo 12-11-2008
Avatar de donald shimoda
donald shimoda donald shimoda is offline
Miembro
 
Registrado: jul 2008
Ubicación: Argentino en Santa Cruz de la Sierra
Posts: 1.083
Poder: 17
donald shimoda Va por buen camino
Cita:
Empezado por Al González Ver Mensaje
¡Hola!

Disculpa que te corrija Donald, pero eso no es lo que hace FreeAndNil. Linett ha dado una explicación más cierta; la variable objeto queda con un valor en blanco (Nil) tras su liberación con FreeAndNil. Es el propio método Free el que hace una validación de seguridad antes de llamar al destructor Destroy.
Tenes absolutamente razón, lo escribí rápido y me olvide que en realidad soy yo el que hago siempre:

Código Delphi [-]
if Assigned(x) then
  FreeAndNil(x);

Esto segun Allen Bauer es un vicio horrendo de programación . Ahora si mirás el código delhi de FreeAndNil:

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

Si obj = nil estas llamando a nil.free!!!! No jodamos, es inaceptable o muy arriesgado para mis pareceres. Aunque se enoje Allen Bauer , escucho argumentos en contra que me quiten el vicio.

Saludos
__________________
Donald Shimoda [Team RO] - Blogs: Remobjects Pascal
Responder Con Cita
  #16  
Antiguo 12-11-2008
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Cita:
Empezado por donald shimoda Ver Mensaje
Si obj = nil estas llamando a nil.free!!!! No jodamos, es inaceptable o muy arriesgado para mis pareceres.
Al contrario. Como comenta Al, es el código de Free (ojo, no el de FreeAndNil) el que verifica que la referencia no sea nil.

Código Delphi [-]
procedure TObject.Free;
begin
  if Self <> nil then
    Destroy;
end;

Justo por eso (y sólo por eso) es que siempre se recomienda usar Free en lugar de Destroy.

// Saludos
Responder Con Cita
  #17  
Antiguo 12-11-2008
Avatar de donald shimoda
donald shimoda donald shimoda is offline
Miembro
 
Registrado: jul 2008
Ubicación: Argentino en Santa Cruz de la Sierra
Posts: 1.083
Poder: 17
donald shimoda Va por buen camino
Cita:
Empezado por roman Ver Mensaje
Al contrario. Como comenta Al, es el código de Free (ojo, no el de FreeAndNil) el que verifica que la referencia no sea nil.
Al contrario de que? No dije lo contrario, mira mas abajo.

Código Delphi [-]procedure TObject.Free; begin if Self <> nil then Destroy; end;


Justo por eso (y sólo por eso) es que siempre se recomienda usar Free en lugar de Destroy.

// Saludos[/quote]

Y te parece segura una llamada como Nil.free ????

Este tema incluso esta referenciado en el blog de Allen Bauer, no todos estan convencidos de una u otra manera. Para mi entre código raro y código seguro : siempre seguro. Eso me permite que un servidor corra 24 horas sin un solo problema.

Saludos.
__________________
Donald Shimoda [Team RO] - Blogs: Remobjects Pascal
Responder Con Cita
  #18  
Antiguo 12-11-2008
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
Cita:
Empezado por donald shimoda Ver Mensaje
...Y te parece segura una llamada como Nil.free ????...
En Delphi es de lo más seguro, Donald.

Cuando el objeto es Nil y el método Free hace esta validación:

Código Delphi [-]
if Self <> nil then
,

está preguntando si Nil es diferente de Nil, en cuyo caso llama a Destroy. De lo contrario no hace absolutamente nada. Si Free fuese un método virtual o hiciera alguna otra cosa con la "improbable" instancia, entonces sí sería inadecuado usarlo en esos casos.

Self es un parámetro implícito que llevan todos los métodos y equivale al puntero en sí de la instancia en cuestión. Nil, cuando el puntero está en blanco. No hay absolutamente ningún problema.

¿Ya convencido?
Responder Con Cita
  #19  
Antiguo 12-11-2008
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Tal como dice Al. Es completamente seguro usar Free en nil. Ese es el objetivo de Free, que sea seguro usarlo. Y lo es porque nunca hay una llamada a nil.Destroy.

// Saludos
Responder Con Cita
  #20  
Antiguo 12-11-2008
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
A ver, borrón y cuenta nueva.

Creo que ya veo por donde va la preocupación de Donald. A él no le inquieta la llamada a Destroy, sino la misma llamada a nil.Free.

Pero creo que hay que recordar que un objeto no es un record. ¿Qué pasa cuando se llama nil.Free? El compilador genera esta llamada:

Código:
mov eax, [eax + ...]
call TObject.Free
Esto es, la función que se llama es TObject.Free que vive en algún lugar de la tabla de métodos de la clase (no el objeto) TObject. Aquí no hay problema entonces, porque TObject existe independientemente de sus instancias. Y a Free se le pasa el parámetro Self que menciona Al, que es la instancia a la que se le aplica el método. Y es ya Free el que protege la llamada al destructor.

// 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
Buenas prácticas de programación elcigarra OOP 18 07-11-2008 18:05:27
Siete prácticas para un óptimo y rápido desarrollo de software poliburro Noticias 5 30-07-2008 17:48:55
buenas maneras... BlueSteel Humor 23 13-06-2008 09:11:21
Buenas Noticias faustoffp Noticias 0 04-09-2006 07:33:06
Ayuda Practicas En Delphi MARIAM23 Varios 1 22-07-2006 02:19:34


La franja horaria es GMT +2. Ahora son las 14:11:24.


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