Delphi - destructor

0

Witam, mam pytanie odnośnie destruktorów w delphi. Poniżej cały kod programu.
Dlaczego u licha destruktor "Free" nie jest wykonywany automatycznie po
opuszczeniu Button1Click??? Przecież kiedy kliknę przycisk wykona się konstruktor,
ale w miejscu gdzie jest: "//Klasa.Free;" kod ten powinien się wykonać, gdyż opuszczana jest procedura Button1Click i tym samym powinna być skasowana z pamięci klasa - czyli de facto wykonany destructror - w tym przypadku o nazwie Free.

 
unit Unit1;

interface

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

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


  TMojaKlasa = class(TObject)
  public
    constructor Create;
    destructor Free;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMojaKlasa }

constructor TMojaKlasa.Create;
begin
  inherited Create;
  ShowMessage('zaczynamy :)');
end;

constructor TMojaKlasa.Create(zmienna: string);
begin
  Inherited Create;
  ShowMessage(zmienna);
end;

destructor TMojaKlasa.Free;
begin
  ShowMessage('konczymy :(');
  inherited Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Klasa : TMojaKlasa;
begin
  Klasa:= TMojaKlasa.Create('chu');
  //Klasa.Free;
end;

end.

0

Sorry namieszałem w powyższym kodzie.
Poniżej jeszcze raz cały kod:

 unit Unit1;

interface

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

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


  TMojaKlasa = class(TObject)
  public
    constructor Create;
    destructor Free;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TMojaKlasa }

constructor TMojaKlasa.Create;
begin
  inherited Create;
  ShowMessage('zaczynamy :)');
end;

destructor TMojaKlasa.Free;
begin
  ShowMessage('konczymy :(');
  inherited Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  Klasa : TMojaKlasa;
begin
  Klasa:= TMojaKlasa.Create;
  //Klasa.Free;
end;

end.
0

A próbowałeś tak?

 TMojaKlasa = class(TObject)
  public
    constructor Create;
    destructor Destroy; override;
  end;
0

Tak, próbowałem tego (czytałem rozdział 7) i niestety efekt ten sam - czyli destruktor nie jest automatycznie wykonany :(( Nie wiem o co chodzi, programowałem kiedyś OOP w starym dobrym C dla DOS - tam destruktory śmigały jak należy. Jeżeli chodzi Wam coś jeszcze po głowie - chętnie spróbuję.

2

a dlaczego niby miałby być??? //Klasa.Free; przecież to się nie wykona bo jest zakomentowane... BTW od kiedy to w Delphi czy C/C++ destruktory są "automatycznie wykonywane"?

0

to prawda jest zakomentowane. Jednakże również w tym miejscu opuszczana jest procedura Button1Click, czyli kasowana jest z pamięci klasa (zobacz gdzie jest ona zadeklarowana). Na tej podstawie śmiem twierdzić, że destructor i tak powinien być wykonany (mechanizm coś jak garbage collector dla .Net). No chyba ze w delphi nie ma takiego mechanizmu??

2

Misiek ma rację. W VCL obiekty są tworzone dynamicznie, z automatu wywoływany jest Destructor tylko dla obiektów posiadających właściciela.
Klasy wyprowadzone bezposrednio z TObject trzeba zwalniać jawnie, inaczej mamy MemoryLeaks.
W twoim przypadku po wyjściu z procedury Button1Click zostanie jedynie utracona informacja o zmiennej Klasa, sam obiekt nadal istnieje.

0

BTW w C++ dla dos destructory z tego co pamiętam w takich sytuacjach są wykonywane automatycznie (właśnie odpowiednik ww mechanizmu G.C.)

0

oki, dzięki za wyjaśnienie. Przyznam że trochę mnie to martwi, no ale cóż, zdecydowałem się na delphi, nie będę się rzucał na coś innego. Po prostu postaram się nie zapominać o metodzie free dla każdego utworzonego obiektu. Dzięki za pomoc panowie. Pozdrawiam i wirtualnego browara stawiam ;)

0
grzesiekyogi__ napisał(a)

Dlaczego u licha destruktor "Free" [...]

Dlaczego tworzysz destruktor z identyfikatorem innej metody...? Dobrze napisał Ci @zibicoder - jak sama nazwa wskazuje, destruktor powinien mieć identyfikator Destroy; "Nadpisałeś" niejako istniejącą metodę Free i podejrzewam, że przez to będą się dziać problemy;

Twórz klasę z głową:

TFooClass = class(TObject)
public
  constructor Create();
  destructor Destroy(); override;
end;

{...}

constructor TFooClass.Create();
begin
  inherited Create();
end;

destructor TFooClass.Destroy();
begin
  inherited Destroy();
end;

Nie ma szans, by wystąpił jakikolwiek konflikt; Poza tym zadeklarowałeś w klasie jedynie jeden konstruktor, a w kodzie dalej masz dwie definicje; I dalej - w destruktorze nie wywołałeś za pomocą słowa inherited destruktora, tylko metodę Free...

2

A teraz trochę teorii. WSZYSTKIE stworzone obiekty są tworzone na stercie. Z tego wynika, że SAM musisz zadbać o ich zwolnienie(jeśli tworzysz dynamicznie). Jeśli obiekt ma rodzica(i właściciela), wtedy on powinien zadbać o jego zwolnienie. Jednak osobiście wolę zawsze sam zwalniać wszystkie obiekty tworzone dynamicznie. Jeśli się mylę, niech mnie ktoś poprawi, bo już lekko wypity jestem ;>.

0

Furious, nie ma znaczenia jaką nadasz nazwę destruktorowi. Równie dobrze może być Free. Mając na myśli "nadpisałeś" podejrzewam, że chodziło Ci o przeciążenie metody - ale uwierz mi, że jest to niemożliwie z przynajmniej 2 powodów:

  1. metoda Free z TObject nie jest metodą virtual ani dynamic
  2. chodzby nawet Free z TObject była virtualna, to ja w definicji nie użyłem słowa "override" powodującego wspomniane nadpisanie.
    Dlatego uważam, że ten fragment kodu jest jak najbardziej w porządku.
    Zgodzę się jedynie z tym, że Destroy jest zalecaną nazwą dla destruktora (ale nie obowiązkową! - no chyba że dla .Net, ale to inna bajka).

Odnośnie definicji 2 konstruktorów masz rację - mój błąd (poprawiłem się w drugim poście od góry). Po prostu testowałem, skopiowałem na forum nie sprawdziwszy czy kod się kompiluje.

Tak czy inaczej wszystko zostało wyjaśnione - delphi dla win32 nie posiada Garbage Collectora - stąd obiekt nie zostanie zwolniony z pamięci po opuszczeniu procedury button1click i będzie miał miejsce wyciek.
W tym miejscu wielkie ukłony dla pana zibicoder, który faktycznie zrozumiał o co mi chodzi i dał mi dokładną odpowiedź, w dodatku przypomniał w jaki sposób poprawnie debugować wycieki pamięci.

Jeszcze raz Wam wszystkim dziękuję, będę dalej uczył się OOP w Delphi, mimo jego minusów (jak wspomiany brak GC).

1
grzesiekyogi napisał(a):

Jeszcze raz Wam wszystkim dziękuję, będę dalej uczył się OOP w Delphi, mimo jego minusów (jak wspomiany brak GC).

To chyba kwestia tzw. gustu. Ja nie lubię GC. Wolę sam mieć nad wszystkim kontrolę.

1 użytkowników online, w tym zalogowanych: 0, gości: 1