2012-08-30 19 views
6

Tengo una duda fundamental en Delphi. Cuando guardo ningún componente en tiempo de diseño, digamos por ejemplo TADOConnectuion y el botón de clic, incluso escribo siguiente código a continuación, no consigo ningún error:Fundamental de "Gratis" en Delphi

begin 
    ADOConnection.Free; //No error 
    ADOConnection.Free; //No error 
    ADOConnection.Free; //No error 
end; 

Pero si creo el mismo objeto en tiempo de ejecución como follwos I obtener "Violación de acceso ..." error

begin 
    ADOConnection := TADOConnection.create(self); 
    ADOConnection.Free; //No error 
    ADOConnection.Free; //Getting an "Access Violation..." error 
end; 

consigo el mismo error aunque se crea el objeto de la siguiente manera:

ADOConnection := TADOConnection.create(nil); 

Sólo me gustaría saber la razón de tal comportamiento, es decir, ¿Por qué no hay ningún error cuando guardo el componente en el momento del diseño?

+1

relacionadas: [¿por qué no FreeAndNil * realmente * nil mi objeto?] (http://stackoverflow.com/questions/8036388/delphi-why-doesnt-freeandnil-really-nil-my-object) – CodesInChaos

+0

Vishal, no es útil (de hecho, se desaconseja) para agregar fórmulas educadas a sus preguntas y respuestas aquí en SO. – mghie

Respuesta

4

Si libera un componente, se borra su campo correspondiente en el propietario. Si agrega un tiempo de diseño ADOConnection, entonces

ADOConnection.Free; // Frees ADOConnection and sets ADOConnection to nil 
ADOConnection.Free; // Does nothing since ADOConnection is nil 

Esto se puede ver mediante la captura en una variable:

var c: TADOConnection; 
c := ADOConnection; 
c.Free; // Frees ADOConnection and sets ADOConnection to nil 
c.Free; // Error: c is not set to nil 

Eso no va a funcionar, incluso cuando se crea ADOConnection en tiempo de diseño.

He aquí un ejemplo con un componente TButton que muestra cómo el comportamiento que se observa para los componentes en tiempo de diseño no es específico de tiempo de diseño de componentes:

unit Unit1; 

interface 

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

type 
    TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    published 
    Button: TButton; 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Assert(not Assigned(Button)); 
    TButton.Create(Self).Name := 'Button'; // Button field gets set 
    Assert(Assigned(Button)); 
    Button.Free;       // Button field gets cleared 
    Assert(not Assigned(Button)); 
    Button.Free;       // Okay, Free may be called on nil values 
end; 

end. 
+1

Última duda, ¿por qué tal comportamiento para el tiempo de diseño y ejecución? hora ? –

+0

@VishalTiwari La diferencia no es realmente entre el tiempo de diseño y el tiempo de ejecución, es entre propiedad y sin dueño. Incluiré un ejemplo en un momento. – hvd

+1

El código relevante que establece ADOConnection como nil está en TComponent.SetReference y no está directamente relacionado con Free, sino más bien con RemoveComponent (que se llama dentro de Destroy). Este mecanismo funciona cuando el propietario tiene un campo que se nombra como el componente secundario. –

3

ADOConnection es inicialmente nulo así que si lo liberas, la función gratuita no hará nada porque el puntero entregado es nulo. El puntero permanece nulo en las llamadas siguientes, por lo que el free no hace nada. Cuando inicie ADOConnection con create, el puntero retenido en ADOConnection ya no es nulo, por lo que la primera llamada a free liberará activamente el puntero, pero las llamadas siguientes verán que la memoria ya se ha liberado y generarán una excepción. El puntero no cambia por la llamada a gratis. Para eso, necesitarías freeandnil en su lugar.

+0

Pero algunas veces la función FreeAndNil también da error de "Violación de Acceso ..." sin ningún motivo, es por eso que estaba trabajando con .Free –

+1

@VishalTiwari: ¿Has visto realmente el código en FreeAndNil? Esa Violación de Acceso ciertamente viene de algún lado, pero no veo cómo podría ser causada por FreeAndNil y no por Gratis ... –

+0

@VishalTiwari: ese tipo de referencia inválida no nula se llama * puntero rancio *. A menos que el destructor esté tan mal escrito que arroje una excepción AV no controlada, la única forma en que recuerdo hacer que FreeAndNil arroje un AV es pasándole un puntero rancio ... –

Cuestiones relacionadas