konto usunięte

Temat: Wskaźniki Self, Nil i Application

Weźmy taki fragment kodu:

var
Label1: TLabel;

procedure TForm1.FormCreate(Sender: TObject);
begin
//wariant pierwszy
Label1:=TLabel.Create(NIL);
//lub wariant drugi
Label1:=TLabel.Create(Self);
//Lub wariant trzeci
Label1:=TLabel.Create(Application);
end;

Pytanie:

W jakich przypadkach lepiej stosować wskaźnik Self, w jakich NIL a w jakich Application? Jaka jest różnica w działaniu programu w przypadku tworzenia komponentu (nie koniecznie TLabel) w przedstawionych powyżej wariantach?
Robert W.

Robert W. Programista

Temat: Wskaźniki Self, Nil i Application

Właściciel komponentu (obiektu), który tworzysz.

W przypadku 1
Label1:=TLabel.Create(NIL);

Label nie ma właściciela. Sam troszczysz się m.in. o zniszczenie obiektu z pamięci.
Label1:=TLabel.Create(Self);

Tutaj już nie musisz się martwić o niszczenie obiektu. Zrobi to właściciel (Self) w tym przypadku forma. Czyli: jak forma ulegnie zniszczeniu dopiero wtedy zniszczy się obiekt.
Label1:=TLabel.Create(Application);

Tutaj niszczeniem zajmie się aplikacja. Jak się zakończy zniszczy obiekt. Wg. mnie jest to dość "niebezpieczne". Można namnożyć obiekty, które należą do "Application" ale tak na prawde niszczą się na zakończenie programu. Jeżeli oczywiście sam tego nie załatwisz.

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Dziekuję za te informacje.

Trzeci sposób z Application powodował niestabilność w moich programach (były wyświetlane odpowiednie komunikaty). Dość często w kodach źródłowych programów spotykałem się z wskaźnikiem Self, rzadziej NIL. Domyślam się że Self stosuje się gdy klasa (tutaj Label1) należy do klasy TForm1 (zadeklarowana w private lub public) a NIL jeżeli nie należy do tej klasy (zadeklarowana np. jako osobna zmienna po var).
Piotr M.

Piotr M. programista

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
Domyślam się że Self stosuje się gdy klasa (tutaj Label1) należy do klasy TForm1 (zadeklarowana w private lub public)

Masakra... a co gdy w protected?

konto usunięte

Temat: Wskaźniki Self, Nil i Application

W przypadku gdy komponent był w sekcji protected stosowałem wskaźnik Self tak samo jak dla private. Komponent Label1 w sekcji protected w tym przypadku będzie widoczny w klasach dziedziczonych od klasy bazowej (w tym przypadku klasą bazową jest TForm1). Taka jest róznica miedzy private a protected.
Nie zauważyłem żeby powodowało to niestabilność w programie (testowałem w Lazarusie). Wszystkie możliwe warianty można przetestować przy użyciu Delphi lub Lazarusa.

konto usunięte

Temat: Wskaźniki Self, Nil i Application

A co mówią mądre księgi?
Marco Cantu, Delphi 7: Praktyka programowania, 2003, t.1, s.85:
"Gdy tworzymy komponent MOŻEMY określić jego właściciela, przekazując go do konstruktora komponentu. Komponent będący właścicielem (najczęściej formularz) staje się odpowiedzialny za usunięcie wszystkich posiadanych przez siebie obiektów. [...]
Tak więc, gdy utworzymy komponent i PRZYPISZEMY mu właściciela, NIE MUSIMY PAMIĘTAĆ o jego usunięciu.
[uwaga:] Takie zachowanie [zabezpieczanie] komponentów tworzonych, przez umieszczanie ich na formularzu lub w module danych podczas projektowania, jest STANDARDOWE.
Jednakże należy wybrać właściciela, który zagwarantuje zniszczenie obiektu". - wszystkie podkr. WB.
Słowo kluczowe "self" oznacza "bieżący obiekt", a więc egzemplarz obiektu danej klasy. W powyższym kodzie oznacza to, że jeśli metoda TForm1.FormCreate zostałaby wywołana więcej niż jeden raz, obiekt poprzednio wskazywany przez Label1 nie zostałby zwolniony, gdyby nie miał przypisanego w konstruktorze właściciela.
Piotr M.

Piotr M. programista

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
W przypadku gdy komponent był w sekcji protected stosowałem wskaźnik Self tak samo jak dla private. Komponent Label1 w sekcji protected w tym przypadku będzie widoczny w klasach dziedziczonych od klasy bazowej (w tym przypadku klasą bazową jest TForm1). Taka jest róznica miedzy private a protected.
Nie zauważyłem żeby powodowało to niestabilność w programie (testowałem w Lazarusie). Wszystkie możliwe warianty można przetestować przy użyciu Delphi lub Lazarusa.

Spoko, wykłady sobie daruj. Zastanawia mnie tylko ile rozumiesz z tego co napisałeś skoro odbijasz się od Ownera TComponent. Tu żywcem nie ma co testować, tymbardziej w kontekście niestabilności. Albo znasz obiekty, albo lecą Ci AV'ały i poprawiasz kod na czuja, domyślając się tu i ówdzie co i jak być może działa.

konto usunięte

Temat: Wskaźniki Self, Nil i Application

W razie wątpliwości możemy skorzystać z dokumentacji Delphi i różnych publikacji o programowaniu. Moim celem jest rozszerzenie wiedzy od strony praktycznej a nie tylko od strony teoretycznej. Cieszę się że na tym forum można się podzielić swoją wiedzą z innymi jak również samemu się wiele nauczyć.Dariusz Rorat edytował(a) ten post dnia 23.11.09 o godzinie 09:51

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Wojciech Błoński:
Tak więc, gdy utworzymy komponent i PRZYPISZEMY mu właściciela, NIE MUSIMY PAMIĘTAĆ o jego usunięciu.

Nie traktujmy tego jako garbage collectora, bo będą memleaki w aplikacji. IMHO lepiej żebyśmy pamiętali i stosowali magiczny blok

Obiekt := TKlasa.Create();
try
// używamy obiektu
finally
Obiekt.Free;
end;

W powyższym kodzie oznacza to, że jeśli metoda TForm1.FormCreate zostałaby wywołana więcej niż jeden raz, obiekt poprzednio wskazywany przez Label1 nie zostałby zwolniony, gdyby nie miał przypisanego w konstruktorze właściciela.

Yy... albo całe życie byłem w błędzie, albo nie masz racji ;-) Nieważne czy z przypisanym ownerem czy nie, jeśli wywołamy drugi raz FormCreate to stworzymy nowy obiekt, przypiszemy go do właściwości/zmiennej Label1 i stracimy informacje o poprzednio stworzonym obiekcie. Takie informacje straci również Owner. Powstaje, więc memleak. Jeśli wiemy, że FormCreate może być wywołane więcej razy musimy samemu zadbać o zwalnianie lub choćby skorzystać z funkcji Assigned() i sprawdzić czy zmienna nie wskazuje na obiekt (choć to też nie jest najlepszym pomysłem).

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Nie traktujmy tego jako garbage collectora, bo będą memleaki w aplikacji. IMHO lepiej żebyśmy pamiętali i stosowali magiczny
blok

Obiekt := TKlasa.Create();
try
// używamy obiektu
finally
Obiekt.Free;
end;

no ale jeśli Label jest tworzony w OnCreate formy, to try/finally tutaj się średnio przyda, bo label będzie zyl przynajmniej jakiś czas. Podanie ewentualnego Ownera dla Labela będzie tutaj tylko w zastosowaniu garbage collectora.

Nieważne czy z przypisanym ownerem czy nie, jeśli wywołamy drugi raz FormCreate to stworzymy nowy obiekt, przypiszemy go do właściwości/zmiennej Label1 i stracimy informacje o poprzednio stworzonym obiekcie. Takie informacje straci również Owner.

Jeśli będzie podany Owner, to ten Owner nie straci i prawidłowo zwolni poprzedniego Labela, kiedy będzie sam umierał.Karol Winnicki edytował(a) ten post dnia 24.11.09 o godzinie 19:34

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Karol Winnicki:
Nie traktujmy tego jako garbage collectora, bo będą memleaki w aplikacji. IMHO lepiej żebyśmy pamiętali i stosowali magiczny
blok

Obiekt := TKlasa.Create();
try
// używamy obiektu
finally
Obiekt.Free;
end;

no ale jeśli Label jest tworzony w OnCreate formy, to try/finally tutaj się średnio przyda, bo label będzie zyl przynajmniej jakiś czas. Podanie ewentualnego Ownera dla Labela będzie tutaj tylko w zastosowaniu garbage collectora.

No tak, tworzenie tymczasowego Labela w FormCreate może nie mieć zbyt dużego sensu. Chodziło mi o bardziej ogólne przypadki.
Nieważne czy z przypisanym ownerem czy nie, jeśli wywołamy drugi raz FormCreate to stworzymy nowy obiekt, przypiszemy go do właściwości/zmiennej Label1 i stracimy informacje o poprzednio stworzonym obiekcie. Takie informacje straci również Owner.

Jeśli będzie podany Owner, to ten Owner nie straci i prawidłowo zwolni poprzedniego Labela, kiedy będzie sam umierał.

Fakt, wycofuję się. Masz rację. Chyba tego jednak do końca nie przemyślałem. ;-)

konto usunięte

Temat: Wskaźniki Self, Nil i Application

a jako ciekawostkę można dodać, że jeśli by Label1 zadeklarować jako IInterface, to nawet gdyby w FormCreate zrobić:


Label1:=TLabel.Create(NIL); //1
Label1:=TLabel.Create(NIL); //2
Label1:=TLabel.Create(NIL); //3


czyli bez Ownera i po kilka razy nawet utworzone, to żadnych memleaków nie będzie i wszystko się samo ładnie zwolni.Karol Winnicki edytował(a) ten post dnia 25.11.09 o godzinie 00:44

konto usunięte

Temat: Wskaźniki Self, Nil i Application

No proszę, taki prozaiczny temat, a jaka ciekawa dyskusja się wywiązała.

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Kacper K.:


Obiekt := TKlasa.Create();
try
// używamy obiektu
finally
Obiekt.Free;
end;

A gdyby użyć FreeAndNil(Obiekt) zamiast Obiekt.Free?. Jak to wpływa na działanie aplikacji?
Robert W.

Robert W. Programista

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
Kacper K.:


Obiekt := TKlasa.Create();
try
// używamy obiektu
finally
Obiekt.Free;
end;

A gdyby użyć FreeAndNil(Obiekt) zamiast Obiekt.Free?. Jak to wpływa na działanie aplikacji?

Gdy użyjesz Obiekt.Free -> zwalniasz obiekt ale wskaźnik do tego obiektu nie jest NIL, wskazuje na coś czego już nie ma.

Używając FreeAndNil(Obiekt), zwalniasz obiekt, a dodatkowo wskaźnik, który na niego wskazuje dostaje "wartość" NIL.
Czyli innymi słowy wykonusze kod:

Obiekt.Free;
Obiekt := nil;Robert W. edytował(a) ten post dnia 27.11.09 o godzinie 07:28

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Robert W.:

Obiekt.Free;
Obiekt := nil;

Z tego co wiem to procedura FreeAndNil najpierw przypisuje wartość NIL do tego obiektu a potem go zwalnia. Tak przynajmniej jest w dokumentacji Free Pascal. Według autorów tej dokumentacji to rekomendowana technika zwalniania obiektu. Nie wiem jak w Delphi. Zapomniałem dodać że chodziło mi tu o wpływ na stabilność aplikacji bo dla mnie to ważne. Bo co jest warty program który ma ukryte błędy.
Robert W.

Robert W. Programista

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
Robert W.:

Obiekt.Free;
Obiekt := nil;

Z tego co wiem to procedura FreeAndNil najpierw przypisuje wartość NIL do tego obiektu a potem go zwalnia. Tak przynajmniej jest w dokumentacji Free Pascal. Według autorów tej dokumentacji to rekomendowana technika zwalniania obiektu. Nie wiem jak w Delphi. Zapomniałem dodać że chodziło mi tu o wpływ na stabilność aplikacji bo dla mnie to ważne. Bo co jest warty program który ma ukryte błędy.

Zgodnie ze źródłami SysUtils:

procedure FreeAndNil(var Obj);
var
Temp: TObject;
begin
Temp := TObject(Obj);
Pointer(Obj) := nil;
Temp.Free;
end;

Widać jak na dłoni co robi FreeAndNil. Chodziło mi o zobrazowanie działania tej procedury.

konto usunięte

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
Robert W.:

Obiekt.Free;
Obiekt := nil;

Z tego co wiem to procedura FreeAndNil najpierw przypisuje wartość NIL do tego obiektu a potem go zwalnia. Tak przynajmniej jest w dokumentacji Free Pascal. Według autorów tej dokumentacji to rekomendowana technika zwalniania obiektu. Nie wiem jak w Delphi. Zapomniałem dodać że chodziło mi tu o wpływ na stabilność aplikacji bo dla mnie to ważne. Bo co jest warty program który ma ukryte błędy.

FreeAndNil stosuje się tylko do property (zmiennych o zasięgu większym niż funkcja). W przypadku zmiennych lokalnych wewnątrz funkcji (bo mamy tu try/finally) czyszczenie wskaźnika nie ma sensu.
Piotr Bartkowski

Piotr Bartkowski zawód:
Technik-Informatyk

Temat: Wskaźniki Self, Nil i Application

Dokładnie to tak wygląda taka procedura FreeAndNil

procedure FreeAndNil(var Obj);
var
P: TObject;
begin
P := TObject(Obj);
TObject(Obj) := nil; // clear the reference before destroying the object
P.Free;
end;
Piotr M.

Piotr M. programista

Temat: Wskaźniki Self, Nil i Application

Dariusz Rorat:
A gdyby użyć FreeAndNil(Obiekt) zamiast Obiekt.Free?. Jak to wpływa na działanie aplikacji?

Wpływa to przede wszystkim tak, że łatwiej wyłapać błędy polegające na odwołaniu się do zwolnionego obiektu, gdyż w jego wnętrzu każde przejście przez selfa kończy się charakterystycznym wyjątkiem AV. Także, jeśli w programie są błędy to FreeAndNil nie sprawi, że nagle same automagicznie znikną.

Następna dyskusja:

Application.MainFormOnTaskBar




Wyślij zaproszenie do