TDecompressionStream.Destroy - co o tym sądzicie?



Wyświetlono wersję archiwalną wątku "TDecompressionStream.Destroy - co o tym sądzicie?" z forum pl.comp.lang.delphi





Bartek Dajewski - 19 Cze 2000, 03:00

Cześć,

Ze zbioru ZLIB.PAS (D3):

destructor TCompressionStream.Destroy;
begin
{...}
  try
{...}
  finally
{...}
  end;
  inherited Destroy;
end;

Czy to jest prawidłowa sekwencja? Przecież jeżeli wystąpi wyjątek w
sekcji try, to nie zostanie wywołany inherited Destroy... Poprawcie mnie
jeśli jestem w błędzie.
---
Pozdrawiam :-)
Bartek



Sławomir Adamski - 19 Cze 2000, 03:00

Witam

destructor TCompressionStream.Destroy;
begin
{...}
  try
{...}
  finally
{...}
  end;
  inherited Destroy;
end;

Czy to jest prawidłowa sekwencja? Przecież jeżeli wystąpi wyjątek w
sekcji try, to nie zostanie wywołany inherited Destroy... Poprawcie mnie
jeśli jestem w błędzie.



Jesteś w błędzie i chyba nieco zmęczony.


Bartek Dajewski - 19 Cze 2000, 03:00

Cześć,

Witam

[...]
|   try
| {...}
|   finally
| {...}
|   end;
|   inherited Destroy;
| end;

| Czy to jest prawidłowa sekwencja? Przecież jeżeli wystąpi wyjątek w
| sekcji try, to nie zostanie wywołany inherited Destroy... Poprawcie
mnie
| jeśli jestem w błędzie.
Jesteś w błędzie i chyba nieco zmęczony.



:-)
Nic nie rozumiem, prawda ?
Czuję się świetnie i nie widzę objawów zmęczenia w powyższym pytaniu

zauważyłem to już po wysłaniu i wcześniej nie prostowałem).
    Wracając do tematu: w razie wystąpienia wyjątku między try a finally
program nie dojdzie do instrukcji inherited Destroy, a to niedobrze.
Moim zdaniem wywołanie destruktora rodzica powinno być zawsze w części
finally, jeżeli istnieje choćby minimalne prawdopodobieństwo wystąpienia
wyjątku. Pytam o ogólną zasadę, a nie o konkretny komponent.
---
Pozdrawiam :-)
Bartek


Sławomir Adamski - 19 Cze 2000, 03:00

Witam



| Witam

[...]
|   try
| {...}
|   finally
| {...}
|   end;
|   inherited Destroy;
| end;

| Czy to jest prawidłowa sekwencja? Przecież jeżeli wystąpi wyjątek w
| sekcji try, to nie zostanie wywołany inherited Destroy... Poprawcie
mnie
| jeśli jestem w błędzie.
| Jesteś w błędzie i chyba nieco zmęczony.

Nic nie rozumiem, prawda ?
Czuję się świetnie i nie widzę objawów zmęczenia w powyższym pytaniu

zauważyłem to już po wysłaniu i wcześniej nie prostowałem).
    Wracając do tematu: w razie wystąpienia wyjątku między try a finally
program nie dojdzie do instrukcji inherited Destroy, a to niedobrze.
Moim zdaniem wywołanie destruktora rodzica powinno być zawsze w części
finally, jeżeli istnieje choćby minimalne prawdopodobieństwo wystąpienia
wyjątku. Pytam o ogólną zasadę, a nie o konkretny komponent.



A co, Twoim zdaniem, przy wystąpieniu wyjątku zostanie wykonane po finally?



Lodek - 19 Cze 2000, 03:00



[...]
|   try
| {...}
|   finally
| {...}
|   end;
|   inherited Destroy;
| end;
    Wracając do tematu: w razie wystąpienia wyjątku między try a finally
program nie dojdzie do instrukcji inherited Destroy, a to niedobrze.



Panie Bartku, jest Pan jednak zmęczony i to chyba solidnie. Jeśli wystąpi
wyjątek pomiędzy try a finally to wykonywanie wejdzie sobie w część finally
- end, a potem pójdzie dalej aż do końcowego end. I tyle. Czyli inherited
Destroy się wykona. Proszę to sobie sprawdzić na jakimkolwiek innym
wyjątku, przykładowo:

try
i:=StrToInt(edit1.Text);
finally
caption:='Ha, jestem tutaj!';
end;
caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
się!';

Była tu jednak kiedyś dyskusja o tym, co będzie jeśli wyjątek wyskoczy w
podsekcji finally - AFAIR stanęło na tym, że będzie ogólna lipa i finally
może nie wykonać się do końca.


Krzysztof Szyszka - 20 Cze 2000, 03:00




| [...]
| |   try
| | {...}
| |   finally
| | {...}
| |   end;
| |   inherited Destroy;
| | end;
|     Wracając do tematu: w razie wystąpienia wyjątku między try a finally
| program nie dojdzie do instrukcji inherited Destroy, a to niedobrze.

Panie Bartku, jest Pan jednak zmęczony i to chyba solidnie. Jeśli wystąpi
wyjątek pomiędzy try a finally to wykonywanie wejdzie sobie w część finally
- end, a potem pójdzie dalej aż do końcowego end. I tyle. Czyli inherited
Destroy się wykona. Proszę to sobie sprawdzić na jakimkolwiek innym
wyjątku, przykładowo:

try
i:=StrToInt(edit1.Text);
finally
caption:='Ha, jestem tutaj!';
end;
caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
się!';



Niestety Panie Lodku Krucafuks nie działa :-) i nie powinno działać.
Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.

[Do Bartka]
Tak, masz rację, twoje rozumowanie jest poprawne, inherited Destroy
nie wykona się, bo nastąpi propagacja wyjątku na wyższy poziom.

BTW. Jak na destruktor, to trochę dziwny kod. Tam raczej nie powinno
być takich kwiatków :-)


Bartek Dajewski - 20 Cze 2000, 03:00

Cześć,





dyskusyjnych
[...]

Niestety Panie Lodku Krucafuks nie działa :-) i nie powinno działać.
Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.

[Do Bartka]
Tak, masz rację, twoje rozumowanie jest poprawne, inherited Destroy
nie wykona się, bo nastąpi propagacja wyjątku na wyższy poziom.



Dziękuję. Bardzo dziękuję, bo już zaczynałem przypuszczać, że źle ze mną
skoro dla moich adwersarzy błąd w rozumowaniu był tak oczywisty, a ja go nie
potrafiłem dostrzec :-) Co prawda pisząc o nich "oboje" możesz się komuś z

BTW. Jak na destruktor, to trochę dziwny kod. Tam raczej nie powinno
być takich kwiatków :-)



To naprawdę jest oryginalny kod Borland'a. W dodatku (według moich
obserwacji D3) po wyjątku w destruktorze pamięć po obiekcie nie zostanie
zwolniona niezależnie od tego, czy będzie tam konstrukcja "try finally end"
czy nie. I jak w takim razie pisać klasy, które np. coś sobie buforują, a
więc w destruktorze powinny bufory opróżnić, a to może się nie udać ?...

---
Pozdrawiam :-)
Bartek


Krzysztof Szyszka - 20 Cze 2000, 03:00


Dziękuję. Bardzo dziękuję, bo już zaczynałem przypuszczać, że źle ze mną
skoro dla moich adwersarzy błąd w rozumowaniu był tak oczywisty, a ja go nie
potrafiłem dostrzec :-) Co prawda pisząc o nich "oboje" możesz się komuś z



Masz rację, mój błąd.
Następnym razem napiszę: flety ;-

| BTW. Jak na destruktor, to trochę dziwny kod. Tam raczej nie powinno
| być takich kwiatków :-)

To naprawdę jest oryginalny kod Borland'a. W dodatku (według moich
obserwacji D3) po wyjątku w destruktorze pamięć po obiekcie nie zostanie
zwolniona niezależnie od tego, czy będzie tam konstrukcja "try finally end"
czy nie. I jak w takim razie pisać klasy, które np. coś sobie buforują, a
więc w destruktorze powinny bufory opróżnić, a to może się nie udać ?...



Poza tym, że dobrze :-), to nie umiem dać Ci ogólnej odpowiedzi na to pytanie.


Lodek - 20 Cze 2000, 03:00


| try
| i:=StrToInt(edit1.Text);
| finally
| caption:='Ha, jestem tutaj!';
| end;
| caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
| się!';

Niestety Panie Lodku Krucafuks nie działa :-) ...



Poprawiłem to na coś takiego i teraz jest OK, takie troszkę niezbyt ładne,
ale działa:

procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
begin
try
  try
  i:=StrToInt(edit1.Text);
  finally
  caption:='Ha, jestem tutaj!';
  end;//tryf
finally
caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
się!';
end;//tryf
end;//proc

... i nie powinno działać.



A czy Pan, Panie Krzysiu, mógłby jakoś wyjaśnić, dlaczego nie dizła to
poprzednie i dlaczego tak właśnie powinno być? Jak dla mnie tak nie powinno
być.

Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.



Przepraszam za wprowadzenie w błąd, byłem tak mocno przekonany, że to co
podałem zadziała, że to posłałem. Cholera, konfuzja zupełna. Pardon.

[Do Bartka]
Tak, masz rację, twoje rozumowanie jest poprawne, inherited Destroy
nie wykona się, bo nastąpi propagacja wyjątku na wyższy poziom.



Kurczę, jak dla mnie to od propagowania wyjątku na wyższy poziom jest
instrukcja raise w exception handlerze. Czy może Pan to wszystko jakoś
dokładnie wyjaśnić.

BTW. Jak na destruktor, to trochę dziwny kod. Tam raczej nie powinno
być takich kwiatków :-)



Panie Bartku, to może niech Pan spróbuje użyć takiego podwójnego try
finally (jednego w drugim) i tak, żeby kluczowy błąd ze względu na
niszczenie obiektu znajdował się w wewnętrznym try finally. Ale ja teraz po
tych rewelacjach to się zakręciłem jak słoik zupełnie.


Sławomir Adamski - 20 Cze 2000, 03:00



dyskusyjnych

grup
| [...]
| |   try
| | {...}
| |   finally
| | {...}
| |   end;
| |   inherited Destroy;
| | end;
|     Wracając do tematu: w razie wystąpienia wyjątku między try a
finally
| program nie dojdzie do instrukcji inherited Destroy, a to niedobrze.

| Panie Bartku, jest Pan jednak zmęczony i to chyba solidnie. Jeśli
wystąpi
| wyjątek pomiędzy try a finally to wykonywanie wejdzie sobie w część
finally
| - end, a potem pójdzie dalej aż do końcowego end. I tyle. Czyli
inherited
| Destroy się wykona. Proszę to sobie sprawdzić na jakimkolwiek innym
| wyjątku, przykładowo:

| try
| i:=StrToInt(edit1.Text);
| finally
| caption:='Ha, jestem tutaj!';
| end;
| caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
| się!';

Niestety Panie Lodku Krucafuks nie działa :-) i nie powinno działać.
Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.



Panie Krzysztofie. Wysoce oceniam Pański poziom wypowiedzi i jestem
niepomiernie zdziwiony. Widać znów nadzszedł czas, aby Pan mnie czegoś
nauczył. Tym razem o wyjątkach. Zróbmy tak:
Nowy projekt, na formę przycisk. Teraz nowa forma (tak, druga) i od razu
usuwamy ją z listy auto_create. Wracamy do pierwszej formy, w implementacji
dopiszemy do uses unit drugiej formy, a do OnClick przycisku wstawmy:

<DELPHI CODE
  try
    Form2.Caption := 'coś tam';
  finally
    MessageDlg('mamy finally', mtInformation, [mbOK], 0);
  end;
  MessageDlg('i po finally', mtInformation, [mbOK], 0);
<?DELPHI CODE
Ja widzę oba komunikaty, a Pan?


Krzysztof Szyszka - 20 Cze 2000, 03:00




| Niestety Panie Lodku Krucafuks nie działa :-) i nie powinno działać.
| Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.

Panie Krzysztofie. Wysoce oceniam Pański poziom wypowiedzi i jestem
niepomiernie zdziwiony. Widać znów nadzszedł czas, aby Pan mnie czegoś
nauczył. Tym razem o wyjątkach. Zróbmy tak:
Nowy projekt, na formę przycisk. Teraz nowa forma (tak, druga) i od razu
usuwamy ją z listy auto_create. Wracamy do pierwszej formy, w implementacji
dopiszemy do uses unit drugiej formy, a do OnClick przycisku wstawmy:

<DELPHI CODE
  try
    Form2.Caption := 'coś tam';
  finally
    MessageDlg('mamy finally', mtInformation, [mbOK], 0);
  end;
  MessageDlg('i po finally', mtInformation, [mbOK], 0);
<?DELPHI CODE
Ja widzę oba komunikaty, a Pan?



Komunikaty, to ja też widzę dwa, za to wyjątku ani jednego ;-)
(proszę sobie sprawdzić, że mimo iż Form2 jest Nil, to podstawienie
pod Caption nie generuje wyjątku !!!).

PS. Te flety, ...hmm... mógł się Pan wykazać większą inwencją. Chyba jest
Pan zmęczony i poziom myślenia coś się Panu obniżył, że nie wspomnę do
jakiego punktu.



Umówmy się, że nie czytałem tego zdania. OK ?

P.S.
Przyznałem się Bartkowi do błędu ortograficznego i to wszystko.
Reszta to gra słów, która z Panami nie ma nic wspólnego.


Krzysztof Szyszka - 20 Cze 2000, 03:00


A czy Pan, Panie Krzysiu, mógłby jakoś wyjaśnić, dlaczego nie dizła to
poprzednie i dlaczego tak właśnie powinno być? Jak dla mnie tak nie powinno
być.

| Oboje ze Sławkiem robicie Bartkowi wodę z mózgu.

Przepraszam za wprowadzenie w błąd, byłem tak mocno przekonany, że to co
podałem zadziała, że to posłałem. Cholera, konfuzja zupełna. Pardon.

| [Do Bartka]
| Tak, masz rację, twoje rozumowanie jest poprawne, inherited Destroy
| nie wykona się, bo nastąpi propagacja wyjątku na wyższy poziom.

Kurczę, jak dla mnie to od propagowania wyjątku na wyższy poziom jest
instrukcja raise w exception handlerze. Czy może Pan to wszystko jakoś
dokładnie wyjaśnić.



W pańskim rozumowaniu wszystko jest OK :-), tylko że ono nie dotyczy
konstrukcji try ... finally end, ale try ... except end.

Konstrukcja try ... finally end NIE GASI zgłoszonego wyjątku, a jedynie
pozwala na wykonanie dodatkowych poleceń zawartych między finally
i end zanim nastąpi jego propagacja na wyższy poziom. Tu nie ma
obsługi wyjątku i dlatego po end nastąpi zerwanie wykonywanie
dalszej części kodu (lub wejście do kolejnej sekcji finally, jak w Pan
drugim przykładzie).

Panie Bartku, to może niech Pan spróbuje użyć takiego podwójnego try
finally (jednego w drugim) i tak, żeby kluczowy błąd ze względu na
niszczenie obiektu znajdował się w wewnętrznym try finally. Ale ja teraz po
tych rewelacjach to się zakręciłem jak słoik zupełnie.



O tym, że tam jest błąd, to Bartek wie, a to jak go poprawić może zależeć
o reszty kodu. Mam nadzieję, że Pana trochę odkręciłem :-)


Krzysztof Swiatkowski - 20 Cze 2000, 03:00


A czy Pan, Panie Krzysiu, mógłby jakoś wyjaśnić, dlaczego nie dizła to
poprzednie i dlaczego tak właśnie powinno być? Jak dla mnie tak nie powinno
być.



Co prawda nie ja byłem wywołany ale...

try finally
jest konstrukcją pozwalającą wykonać jakieś operacje które muszą się wykonać
pomimo wyjątku. Do takich operacji należy np zwolnienie pamięci. Nie
powoduje to jednak wyłapania wyjatku.

0.begin
1. X := TObject.Create;
   try
2.   StrToInt('Wyjatek');
   finally
3.   X.Free;
4.   ShowMessage('No to czyscimy');
   end;
5. ShowMessage('Poza tryf');
6.end;

w przypadku wystąpienia wyjątku (jak powyżej) sekwencja wykonania jest taka:
0,1,2,[3,4],6
gdyby wpisać poprawną wartość to
0,1,2,[3,4],5,6

jak łatwo zauwazyć zestaw [3,4] wykona się zawsze niezależnie od tego czy
wystąpi wyjątek czy nie.

I do tego właśnie słuzy try finally

Kurczę, jak dla mnie to od propagowania wyjątku na wyższy poziom jest
instrukcja raise w exception handlerze. Czy może Pan to wszystko jakoś
dokładnie wyjaśnić.



cytat z helpa
If an exception is raised but not handled in the finally clause, that
exception is propagated out of the try...finally statement, and any
exception already raised in the try clause is lost. The finally clause
should therefore handle all locally raised exceptions, so as not to disturb
propagation of other exceptions.
**
raise  służy do propagowania wyjątku na zewnątrz klauzuli try except. ale
tam jest inny sposób obsługi klauzula try except wyłapuje wyjątki a try
finally nie.
poza tym mozna też danego wyjątku w try except nie wyłapać.

p := nil;

try
  StrToInt('Wyjątek');
  p^ := 'a';
except
  on E:EConvertError do begin

  end
end;

podsumowując kod w klauzuli except wywoła się tylko w przypadku wystapienia
wyjatku a kod w klauzuli finally wywoła się zawsze! albo prawie zawsze o ile
wewnątrz też wystąpi jakiś wyjątek.

I tak dodatkowo. W destruktorze nie powinna sie pojawić instrukcja która
powodowała by wyjątek. W destruktorze się zasadniczo nic nie powinno robić.
Od D4 w wzwyż można do robienia czegoś wykorzystać funkcję
BeforeDestruction. jak w niej się coś wywali to destruktor sie po prostu nie
wywoła.

Hopbit


Bartek Dajewski - 20 Cze 2000, 03:00

Cześć,

[...]

<DELPHI CODE
 try
   Form2.Caption := 'coś tam';
 finally
   MessageDlg('mamy finally', mtInformation, [mbOK], 0);
 end;
 MessageDlg('i po finally', mtInformation, [mbOK], 0);
</DELPHI CODE
Ja widzę oba komunikaty, a Pan?



Widzę oba, ale to jest zupełnie inny przypadek. Ja pisałem o wyjątku miedzy
try a finally. Jeżeli po podstawieniu do Caption wpisać np. abort, będzie
widać tylko jeden komunikat.
---
Pozdrawiam :-)
Bartek


Bartek Dajewski - 20 Cze 2000, 03:00

Cześć,

[...]

| try
| i:=StrToInt(edit1.Text);
| finally
| caption:='Ha, jestem tutaj!';
| end;
| caption:=caption+' I tutaj też! Krucafuks, niemożliwe, a jednak stało
| się!';

| Niestety Panie Lodku Krucafuks nie działa :-) ...
| ... i nie powinno działać.

A czy Pan, Panie Krzysiu, mógłby jakoś wyjaśnić, dlaczego nie dizła to
poprzednie i dlaczego tak właśnie powinno być? Jak dla mnie tak nie powinno
być.



Z HELP-a: "If an exception is raised in the try statement list, control is
transferred to the finally statement list, and once the finally statement
list completes execution, the exception is re-raised" - czyli, że
"gwarantowane" są tylko instrukcje między finally a end (finally statement
list), a następne już nie.
[...]

Panie Bartku, to może niech Pan spróbuje użyć takiego podwójnego try
finally (jednego w drugim) i tak, żeby kluczowy błąd ze względu na
niszczenie obiektu znajdował się w wewnętrznym try finally. Ale ja teraz po
tych rewelacjach to się zakręciłem jak słoik zupełnie.



Nie chodziło mi o to jak sobie poradzić z tym konkretnym komponentem, tylko
raczej o ogólną zasadę poprawnego pisania destruktorów. A teraz - po
odkryciu, że po wyjątku w destruktorze nie jest (!) zwalniana pamięć po
komponencie to już sam nie wiem o co pytać i tylko liczę na to, że moja
metoda sprawdzania jest błędna, a jeżeli nie, to, że w kolejnych wersjach
Delphi błąd ten został usunięty. Może to ktoś sprawdzić ?...
Ja sprawdzałem tak, że tworzę i usuwam wiele razy ten sam komponent i
sprawdzam jego adres. Ten adres się nie zmienia w przypadku bezbłędnego
wykonania metody Free, natomiast jeżeli któreś jej wywołanie zostanie
zakłócone wyjątkiem - następne przydzielane adresy już są inne i tak aż do
następnego wyjątku. Nie umiem sobie tego inaczej wytłumaczyć niż tak, że ta
pamięć ciągle jest "zajęta".
---
Pozdrawiam :-)
Bartek


Robert Keller - 20 Cze 2000, 03:00


Cześć,

Ze zbioru ZLIB.PAS (D3):

destructor TCompressionStream.Destroy;
begin
{...}
  try
{...}
  finally
{...}
  end;
  inherited Destroy;
end;

Czy to jest prawidłowa sekwencja? Przecież jeżeli wystąpi wyjątek w
sekcji try, to nie zostanie wywołany inherited Destroy... Poprawcie mnie
jeśli jestem w błędzie.
---
Pozdrawiam :-)
Bartek



Z tego co wiem prawidłowo powinno być tak :

( Przykład może deczko inny ale zasada ta sama)

function MyFunction: Boolean;

 var MyObject: TMyObject;

begin

result := True;

MyObject := TMyObject.Create;

try          // Dla sekcji finally
 try         // Dla sekcji except

 { coś tam, coś tam, jakieś mętne obliczenia ...
  gdy wystąpi wyjątek program przejdzie kolejno do bloku except a potem
do        finnaly }

 except on E.Exception do
  begin
    result := False;
   ShowMessage('O kurka mamy : ' + E.Message);
  end;
end;

 finnaly
   MyObject.Free;  // I to zadziała zawsze czy był, czy nie był wyjątek.
end;

// A w tej część zachodzą tzw. REGUŁY HAZARDU.

end;

Jeśli jest tu coś nie tak to piszcie i palcie mnie na stosie za herezję.

PS. Dajcie jakiś przykład na zkompresowanie przy użyciu Zlib pliku
"C:\Test\readme.txt".Nie mam CD i nie mam pliku zlib.pas


Lodek - 20 Cze 2000, 03:00


Ok, bardzo Panom dziękuję za "odkręcenie" mnie w kewstii wyjątków i except
\ finally. Panie Bartku, to myślę, że nie trzeba załamywać rąk, tylko tak

jakiś handler na wypadek, gdyby destruktor się nie wykonał, lub wykorzystać
OnBeforeDestroy. Jeszcze się może całkiem nie odkręciłem, ale tak mi się
wydaje. Jeśli finally gdzieś wewnątrz nie zgasi ewentualnego wyjątku to i
tak złapie go except i tam będzie można rozprawić się z sytuacją.


Lodek - 20 Cze 2000, 03:00


[ciach]

| PS. Te flety, ...hmm... mógł się Pan wykazać większą inwencją. Chyba
jest
| Pan zmęczony i poziom myślenia coś się Panu obniżył, że nie wspomnę do
| jakiego punktu.

Umówmy się, że nie czytałem tego zdania. OK ?



Hmmm, ..... no to może najpierw wróćmy do kwestii umówienia się czy myśmy
czytali Pańskie dictum, a potem dopiero będzie Pan - pardon - mędrkował o
umawianiu się w kolejnej kwestii, dobrze? Wie Pan, prawie każdemu zdarza
się czasem odwalić małą chamówę, ale żeby się jeszcze przy tym upierać?


Lodek - 20 Cze 2000, 03:00


Masz rację, mój błąd.
Następnym razem napiszę: flety ;-



Hmmm ....

No, to może niech Pan jednak tak nie pisze, bo się pogniewamy.


Krzysztof Szyszka - 20 Cze 2000, 03:00


Hmmm, ..... no to może najpierw wróćmy do kwestii umówienia się czy myśmy
czytali Pańskie dictum, a potem dopiero będzie Pan - pardon - mędrkował o
umawianiu się w kolejnej kwestii, dobrze? Wie Pan, prawie każdemu zdarza
się czasem odwalić małą chamówę, ale żeby się jeszcze przy tym upierać?



Czy wyście obaj ze Sławkiem powariowali na punkcie tych fletów,  czy ze mną
jest już naprawdę coś nie tak. To nie było ani o Was, ani do Was !!!

Bartek wytknął mi błąd, że o dwóch facetach nie pisze się "oboje" tylko "obaj"
i przyznałem mu rację. Do tego pozwoliłem sobie na takie słowne skojarzenie,

proso, bo prościej. I tam było wyraźnie zaznaczone, że to jest żart. Jak teraz
mam się z tego żartu już drugi raz tłumaczyć, to chyba powinienem pojechać
na urlop i przestać sobie żartować na tym forum, bo mi się wkrótce wszyscy
poobrażają.

Obydwu urażonych Panów niniejszym przepraszam, choć nawet przez myśl
mi nie przeszło "odwalać małej chamówy", jak Pan to ładnie ujął, bo i po co
miałbym to robić udzielając Panu jednocześnie rzeczowej odpowiedzi.

P.S.
Obój, instrument muzyczny dęty drewniany, o wysokiej skali, dźwięku nieco nosowym.
Flet, instrument muzyczny dęty drewniany, o wysokiej skali i miękkim dźwięku.


Fiedzia - 20 Cze 2000, 03:00



| Masz rację, mój błąd.
| Następnym razem napiszę: flety ;-

Hmmm ....

No, to może niech Pan jednak tak nie pisze, bo się pogniewamy.



Widzę, że nie zrozumiałeś dowcipu - oboje i flety to instrumenty muzyczne.

Pozdrawiam


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

[...]

po wyjątku w destruktorze nie jest (!) zwalniana pamięć po
komponencie



Niestety - nie myliłem się: jeżeli podczas wykonywania destruktora wystąpi
wyjątek, to nie zostanie wywołana procedura _ClassDestroy a w konsekwencji
metoda FreeInstance, a więc pamięć nie zostanie zwolniona :-((( Sprawdziłem
to wczoraj u kumpla na D4 i u siebie na D3. W takim razie pytania:
    - czy ktoś to może sprawdzić na D5 ?
    - czy ktoś ma pomysł na prawidłową metodę pisania komponentów, które w
destruktorze muszą jeszcze wykonać jakieś "ryzykowne" operacje. To nie jest
wcale takie nietypowe, bo dotyczy np. wszystkich komponentów, które
funkcjonują na zasadzie bufora danych i przy ich niszczeniu muszą coś zrobić
z zawartością bufora. Jedynie konstrukcja:
try
   {...}
except
end;
daje gwarancję zwolnienia pamięci, ale jest opisana w HELP-ie jako
niezalecana (choć nie potrafię tego fragmentu teraz znaleźć), a poza tym
powoduje wygaszenie każdego wyjątku bez komunikatu o nim. Jak się nie
obrócić d*a z tyłu :-(.

Destruktor w D3 i D4 wygląda tak:
destructor Klasa.Destroy;
begin
    {kod wpisany przez człowieka}
// <auto= kod generowany automatycznie przez kompilator
   if ShouldFreeInstance then
      FreeInstance;
// </auto
end;
gdzie ShouldFreeInstance jest wymyśloną nazwą niejawnego parametru
przekazywanego do destruktora, a informującego o tym, czy pamięć ma być
zwolniona. Przy wywołaniu zmienna.Destroy lub Free ma on wartość True, a
przy wywołaniu inherited Destroy - wartość False.

... a (na mój rozum) powinno być tak:
destructor Klasa.Destroy;
begin
// <auto
    try
// </auto
        {kod wpisany przez człowieka}
// <auto
    finally
        if ShouldFreeInstance then
            FreeInstance;
    end;
// </auto
end;
Tylko, że samemu nie da się tego zrobić - to musi być wbudowane w
kompilator.
---
Pozdrawiam :-)
Bartek


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

[...]

Jeśli jest tu coś nie tak to piszcie i palcie mnie na stosie za herezję.



Wszystko prawda, ale jest kłopot z komponentami, które wewnątrz destruktora
mogą wygenerować wyjątek - chodzi o zwalnianie pamięci. Nieco szerzej o tym
w tym samym wątku list z 20.06.2000 17:20 i następne.

PS. Dajcie jakiś przykład na zkompresowanie przy użyciu Zlib pliku
"C:\Test\readme.txt".Nie mam CD i nie mam pliku zlib.pas



Piszę z pamięci:
var src, dst : TFileStream;
    cmpr : TCompressionStream;
begin
    src := nil;
    dst := nil;
    cmpr := nil;
    try
        src := TFileStream.Create('C:\Test\readme.txt', fmReadOnly);
        dst := TFileStream.Create('spakowany.cośtam', fmCreate);
        cmpr := TCompressionStream.Create(dst, rodzaj_kompresji{fast, max
itp.});
        cmpr.CopyFrom(src, 0);
    finally
        cmpr.Free;
        dst.Free;
        src.Free;
    end;
end;
---
Pozdrawiam :-)
Bartek


Lodek - 21 Cze 2000, 03:00


PS. Dajcie jakiś przykład na zkompresowanie przy użyciu Zlib pliku
"C:\Test\readme.txt".Nie mam CD i nie mam pliku zlib.pas



Leci na priva grzeczniutki zlibek.


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

Nie mam CD i nie mam pliku zlib.pas



Pod adresem <ftp://ftp.freesoftware.com/pub/infozip/zlib/znajdziesz pełny
zestaw źródeł (i to nowszych niż na moim Delphi-CD) i dokumentacji. To jest
FreeWare. Gdybyś miał jakiś problem ze ściągnięciem - daj znać, mogę
podrzucić na PRIV. ZLIB.PAS ma 16Kb, ZLIB.DCU (do D3) ma 48Kb, a zlib.zip ma
219Kb. ZLIB.PAS nie zawiera źródeł kompresujących i dekompresujących - tylko
definicję TCompression/DecompressionStream i korzysta z gotowych funkcji

ZLIB.ZIP zawiera wszystko, również przykłady dla różnych platform i języków
programowania.
---
Pozdrawiam :-)
Bartek


Krzysztof Szyszka - 21 Cze 2000, 03:00


Destruktor w D3 i D4 wygląda tak:
destructor Klasa.Destroy;
begin
    {kod wpisany przez człowieka}
// <auto= kod generowany automatycznie przez kompilator
   if ShouldFreeInstance then
      FreeInstance;
// </auto
end;
gdzie ShouldFreeInstance jest wymyśloną nazwą niejawnego parametru
przekazywanego do destruktora, a informującego o tym, czy pamięć ma być
zwolniona. Przy wywołaniu zmienna.Destroy lub Free ma on wartość True, a
przy wywołaniu inherited Destroy - wartość False.



To jest jakieś kuriozum i ja bałbym się czegoś takiego używać w swoim
programie. Destruktor to jest destruktor, który ma bez obcyndalania się
zwolnić całą pamięć zaalokowaną przez dany obiekt. Koniec filozofii na
temat destruktorów. Jeżeli mogą się z tym wiązać jakieś inne problemy,
to należy rozwiązać je albo w innym miejscu, albo w inny sposób, albo


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,





dyskusyjnych
[...]

| gdzie ShouldFreeInstance jest wymyśloną nazwą niejawnego parametru
| przekazywanego do destruktora, a informującego o tym, czy pamięć ma być
| zwolniona. Przy wywołaniu zmienna.Destroy lub Free ma on wartość True, a
| przy wywołaniu inherited Destroy - wartość False.

To jest jakieś kuriozum i ja bałbym się czegoś takiego używać w swoim
programie. Destruktor to jest destruktor, który ma bez obcyndalania się
zwolnić całą pamięć zaalokowaną przez dany obiekt. Koniec filozofii na
temat destruktorów. Jeżeli mogą się z tym wiązać jakieś inne problemy,
to należy rozwiązać je albo w innym miejscu, albo w inny sposób, albo



Jeżeli pisząc kuriozum masz na myśli "if ShouldFreeInstance then ...", to
jesteś w błędzie. Używasz tego w programie i to nagminnie, a teraz się bój
;-). Zajrzyj do okienka CPU Window przy uruchamianiu krokowym a sam się
przekonasz. Taka jest strategia działania destruktorów odkąd pamiętam i to
tak samo w paskalu jak w C. Destruktor musi wiedzieć czy ma zwolnić pamięć i
musi (!) jej czasem nie zwalniać. Dlaczego? A dlatego, że pisząc
zmienna.Destroy pośrednio wywołujesz wiele destruktorów z klas "rodziców", a
tylko raz FreeMem. To jest tak samo jak z konstruktorem: Klasa.Create to
wszystkie odziedziczone konstruktory, ale tylko jeden GetMem. W dodatku
konstruktor klasy nadrzędnej nie wie jaki jest jej aktualny rozmiar, bo
każda klasa potomna mogła sobie dorzucić jakieś zmienne. Kompilator
przekazuje do wszystkich metod niejawne parametry. Gdyby próbować zapis
obiektowy zastąpić klasycznym i w ten sposób ujawnić wszystkie niejawne
parametry, to wyglądałoby to mniej więcej tak:
    zmienna.Destroy; =Destroy(zmienna, True);
    inherited Destroy; =Destroy(Self, False);
i nie ma na to rady - tak musi być. Mnie się tylko nie podoba, że wywołanie
FreeInstance nie jest w jakiejś (niejawnej) klamrze typu finally .. end; To
samo dotyczy również zwalniania pamięci po Stringach zadeklarowanych
wewnątrz klasy. W normalnych warunkach są zwalniane przez destruktor, ale w
przypadku wystąpienia wyjątku - pamięć nie będzie zwolniona. Im dokładniej
temu się przyglądam tym czarniej to widzę. Wniosek: nie wolno dopuszczać do
wystąpienia wyjątku wewnątrz destruktora!!! Tylko co zrobić, jeżeli taki
wyjątek wystąpi z przyczyn niezależnych ?... :-(
---
Pozdrawiam :-)
Bartek


Krzysztof Swiatkowski - 21 Cze 2000, 03:00



   - czy ktoś ma pomysł na prawidłową metodę pisania komponentów, które w
destruktorze muszą jeszcze wykonać jakieś "ryzykowne" operacje. To nie jest
wcale takie nietypowe, bo dotyczy np. wszystkich komponentów, które
funkcjonują na zasadzie bufora danych i przy ich niszczeniu muszą coś zrobić
z zawartością bufora. Jedynie konstrukcja:



Przy niszczeniu jest już trochę późno na robienie czegokolwiek. Spróbuj z
funkcją BeforeDestruction.

try
  {...}
except
end;
daje gwarancję zwolnienia pamięci, ale jest opisana w HELP-ie jako
niezalecana (choć nie potrafię tego fragmentu teraz znaleźć), a poza tym
powoduje wygaszenie każdego wyjątku bez komunikatu o nim. Jak się nie
obrócić d*a z tyłu :-(.



try

except
  ShowException(ExceptObject, ExceptAddr);
 // albo
 { ExceptionErrorMessage(ExceptObject, ExceptAddr, pC, 255);
  OutputDebugString(pC); }
end;

... a (na mój rozum) powinno być tak:
destructor Klasa.Destroy;
begin
// <auto
   try
// </auto
       {kod wpisany przez człowieka}
// <auto
   finally
       if ShouldFreeInstance then
           FreeInstance;
   end;
// </auto
end;



A czemu nie:
try
  //blah blah
finally
  inherited Destroy;
end;

Hopbit


Krzysztof Szyszka - 21 Cze 2000, 03:00


Jeżeli pisząc kuriozum masz na myśli "if ShouldFreeInstance then ...", to
jesteś w błędzie. Używasz tego w programie i to nagminnie, a teraz się bój
;-).



Nigdy nie bałem się rzeczowej krytyki i nadal nie zamierzam sie bać:-)

Zajrzyj do okienka CPU Window przy uruchamianiu krokowym a sam się
przekonasz. Taka jest strategia działania destruktorów odkąd pamiętam i to
tak samo w paskalu jak w C. Destruktor musi wiedzieć czy ma zwolnić pamięć i
musi (!) jej czasem nie zwalniać. Dlaczego? A dlatego, że pisząc
zmienna.Destroy pośrednio wywołujesz wiele destruktorów z klas "rodziców", a
tylko raz FreeMem.



Wszystko się zgadza, tylko to dotyczy szczegółów implementacji dziedziczenia,
na które ja nie mam żadnego wpływu i co więcej, nawet nie muszę ich znać
żeby tworzyć poprawne konstruktory/destruktory. Ja zrozumiałem, że ty chcesz
taką metodę wprowadzić przy pisaniu destruktora własnego obiektu.

To jest tak samo jak z konstruktorem: Klasa.Create to
wszystkie odziedziczone konstruktory, ale tylko jeden GetMem. W dodatku
konstruktor klasy nadrzędnej nie wie jaki jest jej aktualny rozmiar, bo
każda klasa potomna mogła sobie dorzucić jakieś zmienne. Kompilator
przekazuje do wszystkich metod niejawne parametry. Gdyby próbować zapis
obiektowy zastąpić klasycznym i w ten sposób ujawnić wszystkie niejawne
parametry, to wyglądałoby to mniej więcej tak:
    zmienna.Destroy; =Destroy(zmienna, True);
    inherited Destroy; =Destroy(Self, False);
i nie ma na to rady - tak musi być. Mnie się tylko nie podoba, że wywołanie
FreeInstance nie jest w jakiejś (niejawnej) klamrze typu finally .. end;



To jest cena obiektowości. Przecież nawet wywołanie dowolnej metody
każdego obiektu wiąże się z niejawnym przekazaniem wskaźnika do tego
obiektu jako pierwszy parametr wywołania. Nie wiem, czemu miałoby mi się
to podobac lub nie podobać.

To samo dotyczy również zwalniania pamięci po Stringach zadeklarowanych
wewnątrz klasy. W normalnych warunkach są zwalniane przez destruktor, ale w
przypadku wystąpienia wyjątku - pamięć nie będzie zwolniona. Im dokładniej
temu się przyglądam tym czarniej to widzę. Wniosek: nie wolno dopuszczać do
wystąpienia wyjątku wewnątrz destruktora!!!



No i w tym momencie dochodzisz (trochę inną drogą) do takich wniosków, jakie
zarówno ja, jak i Hobbit próbujemy Ci przekazać.

Tylko co zrobić, jeżeli taki wyjątek wystąpi z przyczyn niezależnych ?... :-(




by nie było już przyczyn niezależnych :-). Jak nic nie skopiesz w programie,
to samo zwolnienie pamięci zawsze się uda. A jak skopiesz, to przyczyna
wyjątku i tak będzie gdzie indziej.


Lodek - 21 Cze 2000, 03:00


[ciach]
P.S.
Obój, instrument muzyczny dęty drewniany, o wysokiej skali, dźwięku nieco
nosowym.
Flet, instrument muzyczny dęty drewniany, o wysokiej skali i miękkim



dźwięku.

[ciach]

Panie Krzysiu, wszystko wyjaśnione. Przepraszam, że się uniosłem. Jakoś nie
zwróciłem uwagi na uwagę Pana Bartka co do "obaj" i stąd lipa. Ciekawe, że
Pan Sławek zareagował tak jak ja.

Znacie ten kawał o Jasiu i Pani psycholog (czy jakoś tak)?


Lodek - 21 Cze 2000, 03:00


z zawartością bufora. Jedynie konstrukcja:
try
   {...}
except
end;
daje gwarancję zwolnienia pamięci, ale jest opisana w HELP-ie jako
niezalecana (choć nie potrafię tego fragmentu teraz znaleźć), a poza tym
powoduje wygaszenie każdego wyjątku bez komunikatu o nim. Jak się nie
obrócić d*a z tyłu :-(.



Cytauję z helpa, pardon że aż tyle, ale to właściwie jest chyba odpowiedź
na to co zacytowałem wyżej:

When an exception is raised, control is transferred to the innermost
exception handler that can handle exceptions of the given class. The search
for an exception handler starts with the most recently entered and not yet
exited try...except statement. If that try...except statement cannot handle
exceptions of the given class, the next most recently entered try...except
statement is examined. This propagation of the exception continues until an
appropriate handler is found, or there are no more active try...except
statements. In the latter case a runtime error occurs and the application
is terminated.

Tu się trochę zdziwiłem: "application is terminated" ?!?!? Hmmmm ... No,
dobra, tak więc jednym rozwiązaniem jest wsadzenie try except w inny try
except. W tym bardziej wewnętrznym reagujemy na krytyczne błędym, a w tym
zewnętrznym na resztę błędów. To tak na mój chłopski rozum. Drugie
rozwiązanie to:

To determine whether the exception block of a try...except statement can
handle a particular exception, the on...do exception handlers are examined
in order of appearance. The first exception handler that lists the
exception class or a base class of the exception is considered a match. If
an exception block contains an else part, and if none of the on...do
exception handlers match the exception, the else part is considered a
match. An exception block that contains only a statement list is considered
a match for any exception.

... i wsadzić obsługę krytycznego błędu na początku bloku except end i
dopisać obsługę reszty w else. Tak to widzę.


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

[...]

Wszystko się zgadza, tylko to dotyczy szczegółów implementacji
dziedziczenia,
na które ja nie mam żadnego wpływu i co więcej, nawet nie muszę ich znać
żeby tworzyć poprawne konstruktory/destruktory. Ja zrozumiałem, że ty
chcesz
taką metodę wprowadzić przy pisaniu destruktora własnego obiektu.



Różnica w naszej ocenie sytuacji bierze się chyba stąd, że dla mnie
wystąpienie wyjątku w destruktorze powinno się dać "naprawić", a według
Ciebie (jeżeli dobrze zrozumiałem) już samo wystąpienie wyjątku jest
niedopuszczalne i należy doprowadzić do sytuacji, kiedy w ogóle nie będzie
miało miejsca. No cóż - z faktami się nie dyskutuje i wygląda na to, że tak
samo ja Ty myślą chłopcy z Borland'a. Od tej pory obiecuję, że na pytanie
"Co sądzisz o obsłudze wyjątków w destruktorach w Delphi?" będę odpowiadał
"Mam na ten temat swoje zdanie, ale je potępiam!".
[...]

| Wniosek: nie wolno dopuszczać do
| wystąpienia wyjątku wewnątrz destruktora!!!

No i w tym momencie dochodzisz (trochę inną drogą) do takich wniosków,
jakie
zarówno ja, jak i Hobbit próbujemy Ci przekazać.



Ale ten wniosek mnie smuci :-( A właściwie bardziej to, że nie ma o tym nic
w HELP-ie. Wszystko pięknie opisane o konstrukcjach try...finally...end, ale
o tym, że w destruktorze nie ma sensu ich stosować to już cisza. Może to
zbyt mocne słowa, ale w destruktorze taka konstrukcja pozwala tylko ratować
co się da, podczas gdy w "zwykłych" procedurach da się uratować wszystko. To
niestety powoduje, że pisząc jakiś komponent musisz o nim wiedzieć prawie
wszystko, żeby po nim dziedziczyć, a nie tylko tyle ile jest potrzebne do
zrealizowania jakiegoś zadania. A to się moim zdaniem kłóci z założeniami
programowania obiektowego i nieco zmniejsza korzyści z niego płynące. A tak
było pięknie, kiedy o tym nie wiedziałem....
---
Pozdrawiam :-)
Bartek
PS. <Erratajest: Hobbit ma być: Hopbit </Errata


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,


|    - czy ktoś ma pomysł na prawidłową metodę pisania komponentów, które w
| destruktorze muszą jeszcze wykonać jakieś "ryzykowne" operacje. To nie
jest
| wcale takie nietypowe, bo dotyczy np. wszystkich komponentów, które
| funkcjonują na zasadzie bufora danych i przy ich niszczeniu muszą coś
zrobić
| z zawartością bufora. Jedynie konstrukcja:

Przy niszczeniu jest już trochę późno na robienie czegokolwiek.



A niby dlaczego? W destruktorze jest jak najlepsze miejsce na zrobienie
porządku po sobie i dokończenie tego, co do tej pory nie zostało dokończone
(tak przynajmniej myślałem). Jeżeli ktoś mi uzasadni dlaczego destruktor nie
powinien kończyć niedokończonych zadań komponentu, to uznam, że zachowanie
Delphi jest poprawne, a błąd jest w moim rozumowaniu. Na razie jednak
uważam, że pozostawianie zajętej pamięci, którego nie da się uniknąć
stosując dostępne mechanizmy jest błędem niezależnie od tego czy jest to
spowodowane wyjątkiem czy nie. Inaczej mówiąc chodzi o to, że Delphi
dostarcza doskonałych konstrukcji do przechwytywania błędów po to, żeby
pisać idiotoodporne programy, a samo - w automatycznie generowanym kodzie -
z tych mechanizmów nie korzysta.
    Wiem, że można to wszystko zrobić inaczej, ale dlaczego nie jest nigdzie

?

Spróbuj z funkcją BeforeDestruction.



Nie mogę - mam D3. Ale rzeczywiście to jest jakieś rozwiązanie dla
szczęśliwych posidaczy nowszych wersji. Postaram się sprawdzić kiedy to się
wywołuje i czy rozwiązuje problem.

| try
|   {...}
| except
| end;
| daje gwarancję zwolnienia pamięci, ale jest opisana w HELP-ie jako
| niezalecana (choć nie potrafię tego fragmentu teraz znaleźć), a poza tym
| powoduje wygaszenie każdego wyjątku bez komunikatu o nim. Jak się nie
| obrócić d*a z tyłu :-(.

try

except
 ShowException(ExceptObject, ExceptAddr);
// albo
{ ExceptionErrorMessage(ExceptObject, ExceptAddr, pC, 255);
 OutputDebugString(pC); }
end;



OK, ale to załatwia tylko sprawę komunikatu na ekranie, a i tak wyjątek jest
gaszony i dalsza jego propagacja ustaje. Miałem na myśli "komunikat" dla
programu w sensie wyjątku, który można przechwycić w kodzie i odpowiednio
zareagować, a nie dla biednego użytkownika, który i tak nic z niego nie
zrozumie ;-)

A czemu nie:
try
 //blah blah
finally
 inherited Destroy;
end;



Jak najbardziej tak, ale dla uproszczenia nie umieściłem tego w moim
przykładzie, bo chciałem w nim tylko zaznaczyć co powinien automatycznie
wygenerować kompilator, a co człowiek. A tak w ogóle, to w świetle tego co
było pisane taki przykład to schizofrenia ;-). Albo zakładam, że wyjątek w
destruktorze może wystąpić i tworzę "sekcje ochronne", albo wiem, że nie
wystąpi i ich nie tworzę. Tylko co mi po tych sekcjach, jeżeli wiem, że przy
wyjątku i tak nie zostanie zwolniona pamięć (nie chodzi mi o wywołanie
inherided Destroy tylko o zwolnienie pamięci)?
    Wniosek <powtarzam się: W Delphi nie wolno dopuścić do wystąpienia
wyjątku w destruktorze, bo powoduje to albo zaśmiecanie pamięci albo
zablokowanie propagacji tego wyjątku tuż po jego wystąpieniu </powtarzam
się. Dla mnie jedno i drugie rozwiązanie jest złe.
    Ciekawostką jest fakt, że w konstruktorze jest kod obsługi wyjątku,
który wywołuje destruktor i zwolnienie pamięci ale wygląda na to, że nie
jest używany - zamiast niego jest wstawione "JMP _HandleAnyException" (mogę
się mylić - tylko przeglądałem procedure _ClassCreate w SYSTEM.PAS).
---
Pozdrawiam :-)
Bartek


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

[...]

This propagation of the exception continues until an
appropriate handler is found, or there are no more active try...except
statements. In the latter case a runtime error occurs and the application
is terminated.

Tu się trochę zdziwiłem: "application is terminated" ?!?!?



Ja też. Mam nadzieję, że to pomyłka i należy rozumieć, że zostaje przerwane
wykonywanie bieżącego ... hmmmm ... nie wiem jak to zgrabnie i krótko
przetłumaczyc: "normal flow of execution in an application".
---
Pozdrawiam :-)
Bartek


Bartek Dajewski - 21 Cze 2000, 03:00

Cześć,

[...]

Znacie ten kawał o Jasiu i Pani psycholog (czy jakoś tak)?



Nie i chętnie poczytam (na otarcie łez wywołanych meritum tego wątku). Byle
było choć trochę krótsze niż słynny już "Thriller rolniczy" ;-) (albo na
PRIV).
---
Pozdrawiam :-)
Bartek


Sławomir Adamski - 21 Cze 2000, 03:00

Witam


dyskusyjnych



[ciach, bo mi wstyd, że strzeliłem taka plamę]
| Ja widzę oba komunikaty, a Pan?

Komunikaty, to ja też widzę dwa, za to wyjątku ani jednego ;-)
(proszę sobie sprawdzić, że mimo iż Form2 jest Nil, to podstawienie
pod Caption nie generuje wyjątku !!!).



No tak, ale swego wstydu nie żałuję. Sporo się dowiedziałem od Pana i innych
dyskutantów.


Sławomir Adamski - 21 Cze 2000, 03:00

Witam

Czy wyście obaj ze Sławkiem powariowali na punkcie tych fletów,  czy ze
mną
jest już naprawdę coś nie tak. To nie było ani o Was, ani do Was !!!

Bartek wytknął mi błąd, że o dwóch facetach nie pisze się "oboje" tylko
"obaj"
i przyznałem mu rację. Do tego pozwoliłem sobie na takie słowne
skojarzenie,

(też instrumenty)



No dobra, wychodzi na to, że to ja mam brudne i włochate myśli.
Przyzwyczajenie drugą naturą człowieka. Za moich młodych czasów za takie coś
dostawało się po ryju, a nie odpowiedź.


Krzysztof Szyszka - 21 Cze 2000, 03:00


Różnica w naszej ocenie sytuacji bierze się chyba stąd, że dla mnie
wystąpienie wyjątku w destruktorze powinno się dać "naprawić", a według
Ciebie (jeżeli dobrze zrozumiałem) już samo wystąpienie wyjątku jest
niedopuszczalne i należy doprowadzić do sytuacji, kiedy w ogóle nie będzie
miało miejsca. No cóż - z faktami się nie dyskutuje i wygląda na to, że tak
samo ja Ty myślą chłopcy z Borland'a.



ROTFL.
To raczej ja przyjąłem rozwiązania chłopców z Borlanda za własne :-)

Od tej pory obiecuję, że na pytanie
"Co sądzisz o obsłudze wyjątków w destruktorach w Delphi?" będę odpowiadał
"Mam na ten temat swoje zdanie, ale je potępiam!".



ROTFL.
To prawie jak moja maksyma:
"Mam na ten temat własne zdanie, ale się z nim nie zgadzam!"

[...]
| Wniosek: nie wolno dopuszczać do
| wystąpienia wyjątku wewnątrz destruktora!!!

| No i w tym momencie dochodzisz (trochę inną drogą) do takich wniosków,
jakie zarówno ja, jak i Hobbit próbujemy Ci przekazać.

Ale ten wniosek mnie smuci :-( A właściwie bardziej to, że nie ma o tym nic
w HELP-ie. Wszystko pięknie opisane o konstrukcjach try...finally...end, ale
o tym, że w destruktorze nie ma sensu ich stosować to już cisza. Może to
zbyt mocne słowa, ale w destruktorze taka konstrukcja pozwala tylko ratować
co się da, podczas gdy w "zwykłych" procedurach da się uratować wszystko.



Zupełnie niepotrzebnie :-). Nie należy ratować, co najwyżej naprawiać, jeśli w
danym momencie potrafisz (try except end), ewentualnie zabezpieczyć sobie
tyły, gdyby się coś nie udało (try finally end). Resztę należy olać !!!

To niestety powoduje, że pisząc jakiś komponent musisz o nim wiedzieć prawie
wszystko, żeby po nim dziedziczyć, a nie tylko tyle ile jest potrzebne do
zrealizowania jakiegoś zadania. A to się moim zdaniem kłóci z założeniami
programowania obiektowego i nieco zmniejsza korzyści z niego płynące. A tak
było pięknie, kiedy o tym nie wiedziałem....



Na otarcie łez powiem Ci, że jak ja stawiałem pierwsze kroki w Delphi, to też
przez pierwsze trzy miesiące próbowałem walczyć z wyjątkami, dopóki nie
zrozumiałem, że tak naprawdę, to one działają na moją korzyść i właściwie
prawie nigdy nie muszę ich obsługiwać !!! Od tego momentu programowanie
w Delphi stało się przyjemnością, a kontrukcji try ... except end używam bardzo,
bardzo rzadko, za to try ... finally end dość często, właściwie to już automatycznie
i ma to ścisły związek z tym co jest PRZED try, a nie MIĘDZY try i finally.

przestaniesz mieć takie dylematy, o jakich teraz piszesz. Ręczę Ci, że każdy

oraz by sam zachowywał się prawidłowo w otoczeniu innych klas Delphi.

Tak naprawdę, to każda nowa klasa jest jedynie drobnym trybikiem w potężnej
maszynie Delphi, która kręci się według własnych reguł i jeśli nie chcesz by
Twój trybik trzeszczał, to dostosuj się do reguł tej maszynki. Chyba, że wolisz
płynąć pod prąd.

PS. <Erratajest: Hobbit ma być: Hopbit </Errata

Nie dam się drugi raz sprowokować :-), nic nie napisze.
Zobacz co rozpętałeś poprzednim razem.


Krzysztof Szyszka - 21 Cze 2000, 03:00


Cześć,

[...]
| This propagation of the exception continues until an
| appropriate handler is found, or there are no more active try...except
| statements. In the latter case a runtime error occurs and the application
| is terminated.

| Tu się trochę zdziwiłem: "application is terminated" ?!?!?

Ja też. Mam nadzieję, że to pomyłka i należy rozumieć, że zostaje przerwane
wykonywanie bieżącego ... hmmmm ... nie wiem jak to zgrabnie i krótko
przetłumaczyc: "normal flow of execution in an application".



Nie ma się co dziwić, tak istotnie jest, tylko na codzień tego nie widać,
bo cała aplikacja kręci się w jednej głównej pętli, w której następuje
obsługa wszystkich wyjątków, które nie zostały wcześnej obsłużone.

Jak wygenerujesz sobie wyjątek w pierwszej instrukcji modułu projektu,
to reszta programu się nie wykona.


Krzysztof Szyszka - 21 Cze 2000, 03:00


No dobra, wychodzi na to, że to ja mam brudne i włochate myśli.
Przyzwyczajenie drugą naturą człowieka. Za moich młodych czasów za takie coś
dostawało się po ryju, a nie odpowiedź.



Jak Panu bardzo na tym zależy, to mogę dać. :-) Może na najbliższym zlocie ?


Krzysztof Szyszka - 21 Cze 2000, 03:00


Panie Krzysiu, wszystko wyjaśnione. Przepraszam, że się uniosłem. Jakoś nie
zwróciłem uwagi na uwagę Pana Bartka co do "obaj" i stąd lipa. Ciekawe, że
Pan Sławek zareagował tak jak ja.



(..............................................)
Kometarz wycięty przez kreator samokontroli,
boś sie Pan zrobił drażliwy jak stado rekinów :-)


Lodek - 21 Cze 2000, 03:00



| Znacie ten kawał o Jasiu i Pani psycholog (czy jakoś tak)?

Nie i chętnie poczytam (na otarcie łez wywołanych meritum tego wątku).
Byle
było choć trochę krótsze niż słynny już "Thriller rolniczy" ;-) (albo na
PRIV).



Kurczę, usłyszałem to w weekend, bedąc na poprawinach po weselu kumpla,
więc umysł i pamięć były nie te, ale powiedzmy, że leci to jakoś tak (Panie
proszę o nie czytanie, chociaż nie jest to [AŻ] TAKI dowcip [który Panowie
sobie opowiadają, jak się nieco rozbawią]):

Na uczelni na zajęciach z psychologii Pani Profesor zadała studentom jako
zadanie domowe (czy pracę semstralną) opracowanie na wybrany z listy temat.
Jasio wybrał temat "Psychoseksualne aspekty zachowania kobiet w zależności
od ich stanu cywilnego".

"Idą ulicą trzy kobiety, każda trzyma w ręku loda. Pierwsza liże swojego
loda, druga ssie, trzecia - gryzie. Ktora z nich jest mężatką?"

Po przeczytaniu pracy Pani Profesor poprosiła Jasia do siebie i mówi:

- Jasiu, myślę, że potraktowałeś temat zbyt powierzchownie, żeby nie
powiedzieć trywialnie lub wręcz zupełnie prostacko i nietrafnie. Co
chciałeś właściwie przekazać w swojej pracy?

A Jaś na to:

- Pani Profesor, bez ogródek! Która była mężatką?

- (profesorka cośtam odpowiada, zawile i z uzasadnieniami)

.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.

- Nie, Pani profesor! Mężątką była ta, która miała obrączkę na palcu, ale
Pani odpowiedź ... to jest właśnie temat mojego opracowania.

Aha, a Thriller Roliczy? Nie podobał się Panu? Co? IMHO Był super i na
czasie. Przynajmniej jak na moje możliwości, chociaż teraz trochę bym to
inaczej zrobił.

Przy okazji tego buga w Wordzie, o którym ostatnio pisali w Enterze to za
jakiś czas, jak będzie chwila, napiszę na listę thriller p.t. "Elektryczny
Kot Bojownik".


Lodek - 21 Cze 2000, 03:00



[...]
| This propagation of the exception continues until an
| appropriate handler is found, or there are no more active try...except
| statements. In the latter case a runtime error occurs and the
application
| is terminated.

| Tu się trochę zdziwiłem: "application is terminated" ?!?!?

Ja też. Mam nadzieję, że to pomyłka i należy rozumieć, że zostaje
przerwane
wykonywanie bieżącego ... hmmmm ... nie wiem jak to zgrabnie i krótko
przetłumaczyc: "normal flow of execution in an application".



No, fano! ale Pan tu wyciął, a to chyba jest rozwiązanie Pana problemu - po
prostu dać try except osadzony w innym try except. W tym wewnętrznym
wyłapywać problemy w sprawach destruktora (o ile dobrze rozumiem problem),
a w tym zewnętrznym resztę. Fakt, że łyso, ale co zrobić innego, hę?


Sławomir Adamski - 21 Cze 2000, 03:00



dyskusyjnych

| No dobra, wychodzi na to, że to ja mam brudne i włochate myśli.
| Przyzwyczajenie drugą naturą człowieka. Za moich młodych czasów za takie
coś
| dostawało się po ryju, a nie odpowiedź.

Jak Panu bardzo na tym zależy, to mogę dać. :-) Może na najbliższym zlocie
?



Pańskie poczucie humoru jest zniewalające. Ale postaram się stawić.


Lodek - 22 Cze 2000, 03:00


(..............................................)
Kometarz wycięty przez kreator samokontroli,
boś sie Pan zrobił drażliwy jak stado rekinów :-)




aluzji, ot co i tyle! A Pan tu o rekinach prawisz i w ogóle. Pańska aluzja

Bartek i stąd zamieszanie.

Nic więcej nie odpisuję tu, bo właśnie na dyskusjach dostałem wyrazy
niezrozumienienia nie tylko mojej odpowiedzi, ale również tego co było
wcześniej w wątku, więc ... cóż, każdemu się zdarza.


Bartek Dajewski - 23 Cze 2000, 03:00

Cześć,



| Znacie ten kawał o Jasiu i Pani psycholog (czy jakoś tak)?

| Nie i chętnie poczytam (na otarcie łez wywołanych meritum tego wątku).
Byle
| było choć trochę krótsze niż słynny już "Thriller rolniczy" ;-) (albo na
| PRIV).



[... kawał o Jasiu]
:-))
Dobre. Znałem to, ale w innej wersji, więc się nie połapałem po pytaniu o
Jasia i Panią psycholog.

Aha, a Thriller Roliczy? Nie podobał się Panu? Co? IMHO Był super i na
czasie. Przynajmniej jak na moje możliwości, chociaż teraz trochę bym to
inaczej zrobił.



No nie, to nie tak!!! Podobał mi się! Pozwoliłem sobie nawet pobrać z www
zbiór thriller_rolniczy.zip, żeby mieć co poczytać, kiedy będzie mi smutno.
A chodziło mi o to, że gdyby rozmiar tego kawału był porównywalny z
thrillerem, to mógłby przekraczać oczekiwania użytkowników grupy związane z

---
Pozdrawiam :-)
Bartek


Bartek Dajewski - 23 Cze 2000, 03:00

Cześć,



[...]
No, fano! ale Pan tu wyciął, a to chyba jest rozwiązanie Pana problemu - po
prostu dać try except osadzony w innym try except. W tym wewnętrznym
wyłapywać problemy w sprawach destruktora (o ile dobrze rozumiem problem),
a w tym zewnętrznym resztę. Fakt, że łyso, ale co zrobić innego, hę?



Wyciąłem, bo chciałem odpowiedzieć później - po dokładniejszym zbadaniu
problemu. Niestety rozwiązanie nadal ma tę samą ułomność: jeżeli w
destruktorze wystąpi wyjątek i nie zostanie zaraz wygaszony przez except -
nie zostanie zwolniona pamięć po komponencie ani po Stringach, które
zawierał (pewnie po Variantach też). I wtedy mamy taką dziwną sytuację - np.
wykonały się wszystkie destruktory, a pamięć nadal jest zajęta.

Badałem, badałem... a oto co wybadałem (wszystko dotyczy D3 i D4. Do D5 nie
miałem dostępu):
Jak się nietrudno domyślić zaraz po destruktorze na tapetę trafił
konstruktor. I tu, ku mojej radości, stwierdziłem, że kod niejawny (1)
zawiera coś w rodzaju konstrukcji try...except...end. Żeby było śmieszniej
jest to rozwiązane trochę inaczej niż zwykle w tego rodzaju konstrukcjach,
bo całość jest w sprytny sposób przeniesiona do innej procedury
(_ClassCreate), a w konstruktorze jest tylko jej wywołanie w dodatku
warunkowe. Ale mniejsza o to, działa to tak, jakby było wpisane w jednym
miejscu. W efekcie konstruktor najwyższego poziomu wygląda tak (2):
dla Delphi 3:
constructor Klasa.Create;
begin
<auto
    NewInstance;
    try
</auto
<wpisał człowiek
{tu jest miejsce dla wszystkich linii wpisanych w implementacji
konstruktora}
{na przykład: inherited Create}
</wpisał człowiek
<auto
    except
        Free;
        raise;
    end;
</auto
end;

Dla Delphi 4:
{początek taki sam}
<auto
    except
        if Self <nil then begin
            Destroy; {wywołany tak, żeby nie wywoływał _ClassDestroy}
                    {... czyli nie zwalniał pamięci}
            _ClassDestroy;
        end;
        raise;
    end;
</auto

Konstruktor wywołany przez inherited Create nie zawiera tych części, które
umieściłem w klamrach <auto, </auto. Tak więc ten sam kod może w
zależności od sposobu wywołania zawierać lub nie zawierać konstrukcji
try...except...end. Trochę to zamotane, ale to jest tak, jakby przy użyciu
if-a "włączać" całą konstrukcję, albo tylko linie zawarte między try a
except.

I to mi się podoba i właśnie czegoś takiego oczekiwałem po kodzie
wygenerowanym przez Delphi. Nadal natomiast nie rozumiem dlaczego ten sam
mechanizm nie funkcjonuje w destruktorze... Przy okazji załączam listę
(pewnie niekompletną) klas, których destruktory zawierają try...cośtam, albo
raise:
TThreadList, TCustomForm, TDataModule, TCompressionStream, TCustomWinSocket,
TDataSet, TField, TBDECallback, TBlobStream, TBitmapCanvas, TOutlineNode.

zaakceptowane przez Borland. A więc jak to jest: można dopuszczać do
wystąpienia wyjątku w destruktorze czy nie? O ile jestem w stanie przyjąć,
że nie można, to w dalszym ciągu mam zastrzeżenia do firmy, że nie opisała
tego wszystkiego w HELP-ie i to WIELKIMI LITERAMI.

(1) kod niejawny - dla uproszczenia tak sobie nazwałem to, co automatycznie
generuje kompilator, a co nie ma bezpośredniego odpowiednika we wpisanych
liniach programu.
(2) konstruktor najwyższego poziomu - czyli zdefiniowany w klasie, która
jest w tej chwili tworzona. Chodzi o wywołania typu Klasa.Create, a nie
dotyczy konstruktorów wywołanych przez inherited Create z wnętrza innych
konstruktorów.
---
Pozdrawiam :-)
Bartek
PS. Nadal ponawiam prośbę o sprawdzenie tego dla D5. Sam spróbuję (jak będę
miał trochę czasu) sprawdzić to na BCB, ale może mi się nie udać, bo mam
tylko wersję Trial (tę z płyty Delphi 3), a ona ma ograniczenia na datę
systemową.


Bartek Dajewski - 23 Cze 2000, 03:00

Cześć,


[...]
| Od tej pory obiecuję, że na pytanie
| "Co sądzisz o obsłudze wyjątków w destruktorach w Delphi?" będę
odpowiadał
| "Mam na ten temat swoje zdanie, ale je potępiam!".

ROTFL.
To prawie jak moja maksyma:
"Mam na ten temat własne zdanie, ale się z nim nie zgadzam!"



Bo to właśnie miało być to samo tylko trochę dosadniej powiedziane :-)

[...]

| w destruktorze taka konstrukcja pozwala tylko ratować
| co się da, podczas gdy w "zwykłych" procedurach da się uratować wszystko.

Nie należy ratować, co najwyżej naprawiać, jeśli w
danym momencie potrafisz (try except end), ewentualnie zabezpieczyć sobie
tyły, gdyby się coś nie udało (try finally end). Resztę należy olać !!!



Rzeczywiście ratować to źle dobrane słowo. Miałem na myśli to co nazwałeś
zabezpieczaniem tyłów.
(Wybaczcie, że tak "obficie" cytuję, ale nie umiałem tak poskracać
wcześniejszych wypowiedzi, żeby pozostawić związek między pytaniem i
odpowiedzią.)

Na otarcie łez powiem Ci, że jak ja stawiałem pierwsze kroki w Delphi, to
też
przez pierwsze trzy miesiące próbowałem walczyć z wyjątkami, dopóki nie
zrozumiałem, że tak naprawdę, to one działają na moją korzyść i właściwie
prawie nigdy nie muszę ich obsługiwać !!! Od tego momentu programowanie
w Delphi stało się przyjemnością, a kontrukcji try ... except end używam
bardzo,
bardzo rzadko, za to try ... finally end dość często, właściwie to już
automatycznie
i ma to ścisły związek z tym co jest PRZED try, a nie MIĘDZY try i finally.

przestaniesz mieć takie dylematy, o jakich teraz piszesz. Ręczę Ci, że
każdy

oraz by sam zachowywał się prawidłowo w otoczeniu innych klas Delphi.

Tak naprawdę, to każda nowa klasa jest jedynie drobnym trybikiem w potężnej
maszynie Delphi, która kręci się według własnych reguł i jeśli nie chcesz
by
Twój trybik trzeszczał, to dostosuj się do reguł tej maszynki. Chyba, że
wolisz
płynąć pod prąd.



Rozumiem, że to nie herezja i sam też podpisuję się pod tym obiema rękami.
Ja nie chcę walczyć z wyjątkami, tylko wiedzieć, że wystąpiły. A cały czas
uważam, że sytuacja, w której wszystkie destruktory się wykonały, a pamięć
jest ciągle zajęta jest niedobra. Tak jak Ty w ogóle (prawie) nie używam
try..except, ale z testów wyszło, że to jedyna metoda doprowadzenia do
zwolnienia pamięci po komponencie. Jeśli Cię jeszcze nie znudził cały ten
problem i moje przydługie wywody - zajrzyj do dzisiejszego listu w tym samym
wątku: "TCompressionStream.Destroy - co o tym sądzicie? :-(wnioski)". Tam
opisałem o konstruktorach, destruktorach i wyjątkach to, co utwierdza mnie w
przekonaniu, że trochę racji mam i że niektóre Borland-owe komponenty też
płyną trochę pod prąd. Po prostu jest pewien rozdźwięk między obsługą
wyjątku w konstruktorze i w destruktorze, a skoro taka obsługa w ogóle
jest - to znaczy, że Borland o tym myślał i wymyślił coś, co <megalomania
IMHO mogłoby być zrobione lepiej </megalomania.

PS. <Erratajest: Hobbit ma być: Hopbit </Errata

Nie dam się drugi raz sprowokować :-), nic nie napisze.
Zobacz co rozpętałeś poprzednim razem.



ale ... ja .... naprawdę ..... nie .... chciałem ..... ;-(
Następnym razem będę bardziej uważał ;-)
---
Pozdrawiam :-)
Bartek


Krzysztof Szyszka - 23 Cze 2000, 03:00


I to mi się podoba i właśnie czegoś takiego oczekiwałem po kodzie
wygenerowanym przez Delphi. Nadal natomiast nie rozumiem dlaczego ten sam
mechanizm nie funkcjonuje w destruktorze... Przy okazji załączam listę
(pewnie niekompletną) klas, których destruktory zawierają try...cośtam, albo
raise:
TThreadList, TCustomForm, TDataModule, TCompressionStream, TCustomWinSocket,
TDataSet, TField, TBDECallback, TBlobStream, TBitmapCanvas, TOutlineNode.

zaakceptowane przez Borland. A więc jak to jest: można dopuszczać do
wystąpienia wyjątku w destruktorze czy nie? O ile jestem w stanie przyjąć,
że nie można, to w dalszym ciągu mam zastrzeżenia do firmy, że nie opisała
tego wszystkiego w HELP-ie i to WIELKIMI LITERAMI.



Daj spokój temu śledztwu, bo dostaniesz obłędu ;-)

bo wolno, skoro program się kompiluje, ale _paktyka_ jest taka, że tam jest
już za późno na naprawianie błędów, a konstrukcję try ... finally end stosuje
się właściwie mechanicznie wszędzie tam, gdy coś działa na zasadzie begin/end
i takie jej zastosowanie masz TCustomForm, TDataModule, innych nie sprawdzałem.

Jeżeli wykonało się BeginWrite, to do pary _musi_ wykonać się EndWrite i nie należy
do tego dorabiać żadnej filozofi (nawet jeśli to występuje w destruktorze), bo taki sposób
pisania jest właściwie automatyczny i po tym (między innym) można poznać dobrą szkołę
programowania w Delphi.

P.S.
Cały czas mam wrażenie, że zamiast szukać przyczyny występowania błędu w destruktorze
próbujesz niwelować jego skutki. Nie obraź się, ale dla mnie to jest takie leczenie sy**
przy
pomocy pudru :-)


Lodek - 23 Cze 2000, 03:00


No nie, to nie tak!!! Podobał mi się! Pozwoliłem sobie nawet pobrać z www
zbiór thriller_rolniczy.zip, żeby mieć co poczytać, kiedy będzie mi



smutno.

Ha, wiedziałem, że w końcu dostąpię sławy, chwały i poklasku! Nowy
Hitchcock!

W czasuie kiedy pisałem stronkę z linkiem do screenów w związku
Cat-Warrior-gate tak się nakręciłem, że aż wynotowałem sobie główne moje
wątki, to jest materiał na taki zakręcony tekst, że normalnie ... Trzeba


Lodek - 23 Cze 2000, 03:00


Kurczę, to jest nieźle zakręcone, wsadzę to do archiwum i jak będę pisał
coś co w zamierzeniach ma chodzić absolutnie przez 7:7\24:24 to sobie to
obadam dokładnie.


Lodek - 23 Cze 2000, 03:00


Wie Pan, Panie Bartku, ja nie mam jakiegoś dużego doświadczenia w pisaniu

zabrałem za jedną rzecz, bo pisanie w kółko tych samych rzeczy mnie
denerwuje, chociaż ma swoje dobre strony %*). No i powiem Panu, że ja
często robię rzecz naganną, tzn. piszę komponent właściwie jakoś tak, że on
nie zawiera innych obiektów, ma właściwie tylko metody - takie coś chyba
jak interface'y (nie znam się na interface'ach, ale to jest chyba coś
takiego). No, poza tym, że są pola, ale nieobiektowe: tylko typy proste, w
tym pointery (wiem, że to nieeleganckie). Przykładowo wygląda to tak, że
aplikacja używająca komponentu musi sama stworzyć dajmy na to TStringList,
następnie podawać ten (tą?) TStringList do mojego komponentu jako parametr
metody, a następnie sama zadbać o zwolnienie TStringList. Podobnie jest z
eventami - po prosty komponent jest tylko od tego, żeby miał OnCośtam, a w
OnCośtam, na zewnątrz komponentu oprogramowuje się jakieś wstawianie do
TStringList, wyświetlanie czegośtam etc.

Wiem, że to może być kłopotliwe, jest trochę może i nieeleganckie, ale w
sumie jakoś się sprawdza.

Czy nie sądzicie, że studia są beznadziejne?
określenie dowolnej współrzędnej do wolnego obrazka w mozilli
jak uniknąć kasuj.php?del_id=$x ?
autoryzacja (trochę długie :))
jak dodać ukośnik
To co z ta gra ?
Tomcat w zastosowaniu produkcyjnym
Nauka - w jakim środowisku
strona grupy
is_int() nie działa
Ruch na grupie....
FPC i wstawki asmowe
Panie Lodku, Panowie ...
java 5-10 razy wolniejsza od php
Upt ?
Zbieranina wiadomości z for dyskusyjnych ; Indeks
Linki,