🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: pl.comp.lang.c
Article #267802

Re: Ciemna strona C++

#267802
From: Sektor van Skijlen
Date: Wed, 05 Dec 2007 13:44
139 lines
8353 bytes
Dnia Tue, 4 Dec 2007 08:43:18 -0800 (PST), Maciej Sobczak skrobie:
> On 3 Gru, 22:50, Sektor van Skijlen

> > PS. Swoją drogą, zauważyłem że na wszystkich tutorialach - nie sprawdzałem
> > dokładnie swojego pod tym względem, ale chyba jest chlubnym wyjątkiem :) -
> > całkowicie ŹLE tłumaczą, jak wygląda obsługa nieoczekiwanego wyjątku i wyjątku
> > poprzez main(), czyli sprawa unexpected() i terminate().
> >
> > Funkcje set_terminate() i set_unexpected() nie służą do ustawiania własnych
> > handlerów wykonujących się ZAMIAST domyślnych (to nie jest "szklanka zimnej
> > wody jako środek antykoncepcyjny"). Handlery te wykonują się PRZED domyślną
> > obsługą.
> [...]

> Nie.
> Funkcje podane przez użytkownika są ZAMIAST a nie PRZED.
> set_terminate() ustawia funkcję, wobec której standard wymaga, aby
> zakończyła program. Nie ma sensu rozważać, co się dzieje potem.

Gdzie tak przepraszam wyczytałeś, bo ja niczego takiego w standardzie nie
widzę (wsiąkł mi gdzieś ISO C++ 2002, mam tylko draft na C++0x, ale tam się
chyba nic nie zmieniło, a przynajmniej wątpię, żeby na gorsze). O funkcji
terminate jest napisane dokładnie tyle, cytuję (18.6.3.3):

void terminate ();

1 Called by the implementation when exception handling must be abandoned for
any of several reasons (15.5.1).
May also be called directly by the program.

2 Effects: Calls the terminate_handler function in effect immediately after
evaluating the throw-expression
(18.6.3.1), if called by the implementation, or calls the current
terminate_handler function, if called by the
program.

Przy set_terminate() też nic na ten temat nie ma:

18.6.3.2 set_terminate [lib.set.terminate]
terminate_handler set_terminate ( terminate_handler f ) throw ();

1 Effects: Establishes the function designated by f as the current handler
function for terminating exception processing.
2 Requires: f shall not be a null pointer.
3 Returns: The previous terminate_handler .

> set_unexpected() ustawia funkcję, wobec której standard wymaga, aby
> nie wracała i dodatkowo nakłada reguły (15.5.2/2), które reagują na
> jej wyjątki - ale standardowa funkcja nie jest już wołana.

Punkt, który podałeś, dotyczy unexpected(), a nie terminate(). Zresztą z
całego 15.5.2 wynika dla mnie, że :

 - unexpected() woła funkcję użytkownika, która może rzucić wyjątkiem
   (domyślnie sama rzuca std::bad_exception)
 - jeśli funkcja ma specyfikację wyjątków i nie wypuszcza typu tego wyjątku,
   rzucany jest wyjątek std::bad_exception. Jeśli tego wyjątku funkcja również
   nie wypuszcza, wywoływane jest terminate()

Niestety z tego opisu nie wynika dla mnie jasno, co się stanie, jeśli
użytkownika handler unexpected() nie zrobi nic. Z tego, co przypuszczam, opis
sugeruje, że jeśli nie zrobi nic, to i tak nastąpi próba rzucenia
std::bad_exception.

Nie jestem jednak o tym aż tak przekonany, bo do powodów, przy których woła
się std::terminate() należy (15.5.1/1):

 - when the implementation's default unexpected exception handler is called
(18.6.2.2)

Czyli jeśli jest wołany jakiś nie-default, to terminate jest "niekoniecznie
wołana"?

Nie ma nigdzie w standardzie takiego zastrzeżenia, że terminate() ma nie
wracać. Co więcej, decyzję, czy zwijać stos gdy terminate() jest wynikiem
wyskoczenia wyjątku z main() [użyłem skrótu myślowego] pozostawia
implementacji - może więc i implementacja decyduje, czy z terminate() można
wracać, czy nie. Wyrażenie "shall not return" jest użyte tylko w stosunku do
unexpected():

18.6.2.2 Type unexpected_handler [lib.unexpected.handler]
typedef void (* unexpected_handler )();
1 The type of a handler function to be called by unexpected() when a function
attempts to throw an exception not
listed in its exception-specification.
2 Required behavior: An unexpected_handler shall not return. See also 15.5.2.
3 Default behavior: The implementation.s default unexpected_handler calls
terminate().

...

18.6.3.1 Type terminate_handler [lib.terminate.handler]
typedef void (* terminate_handler )();
1 The type of a handler function to be called by terminate() when terminating
exception processing.
2 Required behavior: A terminate_handler shall terminate execution of the
program without returning to the
caller.
3 Default behavior: The implementation.s default terminate_handler calls
abort().

Czy na podstawie standardu jesteś więc w stanie określić, czy:
 - wolno nie kończyć programu w terminate()
 - implementacji wolno utłuc program abort()-em jeśli użytkownik nie ubije
   wcześniej programu w swoim handlerze terminate()?

> Nie ma tu żadnego PRZED. To jest ZAMIAST.

Po raz kolejny wytłumaczę się w ten sposób: może i standard nie wyraża się
wprost, że jest to PRZED, tylko mówi, że niby ZAMIAST, ale i tak musisz
zakończyć program. Ale takie tłumaczenie jest niepotrzebnie zbyt
skomplikowane, a praktyka jest po prostu prostsza.

Nie przyglądałem się, jak to jest w standardzie - o tym, że oryginalna
terminate() i tak jest wołana po funkcji użytkownika, przeczytałem w DEC++.

Nie wiem, na ile jest to sprawa implementacji, ale jedynym sposobem wymuszenia
na użytkowniku, żeby w swoim handlerze spowodował zakończenie programu jest
spowodowanie zakończenia programu po jej zakończeniu. Ponieważ w domyślnej
sytuacji nic innego nie robi (a kończy program i tak w ten sam sposób), więc
metodą logicznej eliminacji jedyną sensowną implementacją spełniającą wymogi
standardu jest wywołać abort() zaraz po wykonaniu funkcji użytkownika -
najwyżej użytkownik zakończy program poprzez exit() zanim do tego dojdzie.

Nie ma jednak, niestety, sposobu na to, żeby uniemożliwić użytkownikowi
odkładanie tego zakończenia ad calendas graecas. W tym wypadku jednak nie
starałbym się aż tak narzucać użytkownikowi czegokolwiek, bo jeśli usiłuje
kontynuować pracę już zepsutej aplikacji, to jego problem.

Ale nawet zakładając, że tak rzecze standard, nie zmienia to faktu: większość
tutoriali twierdzi stanowczo, że funkcja ta używana jest ZAMIAST oryginalnego
handlera, "trochę zapominając" wspomnieć, że funkcja ta MUSI spowodować
również zakończenie programu

-- 
//  _    ___         Michal "Sektor" Malecki <sektor(whirl)kis.p.lodz.pl>
\\ L_ |/ `|  /^\ ,()                         <ethouris(O)gmail.com>
// \_ |\  \/ \_/ /\ C++ bez cholesterolu: http://www.intercon.pl/~sektor/cbx
"Java is answer for a question that has never been stated"
Technical Details
Message-ID: <fj69vc$te$1@kujawiak.man.lodz.pl>
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.rmf.pl!agh.edu.pl!news.agh.edu.pl!newsfeed.silweb.pl!news.man.lodz.pl!not-for-mail
References: <fghgeo$spf$1@nemesis.news.tpi.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <1195688300.8426.30.camel@qrnik> <fi3ems$7ig$1@kujawiak.man.lodz.pl> <1195734091.8426.77.camel@qrnik> <fi6n5f$fpr$1@kujawiak.man.lodz.pl> <1195858230.20523.107.camel@qrnik> <fie2un$cbn$1@kujawiak.man.lodz.pl> <1196076390.30869.52.camel@qrnik> <fj1tmo$52u$1@kujawiak.man.lodz.pl> <1101d6ea-b312-4214-b153-8e1cc26a99ba@n20g2000hsh.googlegroups.com>

Show Full Headers
Complete Article Headers
Path: mbox-mo1.pugleaf.net!news-archive.icm.edu.pl!news.rmf.pl!agh.edu.pl!news.agh.edu.pl!newsfeed.silweb.pl!news.man.lodz.pl!not-for-mail
From: Sektor van Skijlen <ethouris@guess.if.gmail.com.is.valid.or.invalid>
Newsgroups: pl.comp.lang.c
Subject: Re: Ciemna strona C++
Date: Wed, 5 Dec 2007 13:44:12 +0000 (UTC)
Organization: LODMAN - Metropolitan Area Network in LODZ, Poland
Lines: 139
Sender: Michal Malecki <sektor@student.kis.p.lodz.pl>
Message-ID: <fj69vc$te$1@kujawiak.man.lodz.pl>
References: <fghgeo$spf$1@nemesis.news.tpi.pl> <fgv6ba$k14$1@bozon2.softax.pl> <fgvkne$u3b$1@news.vectranet.pl> <fh1tjd$dtt$1@bozon2.softax.pl> <fh2lj6$qkh$1@news.vectranet.pl> <fha3as$pap$1@bozon2.softax.pl> <fhaj8u$e02$1@news.vectranet.pl> <fhf09d$ohq$1@bozon2.softax.pl> <fhfi9l$640$1@news.vectranet.pl> <fhurmu$5d9$1@bozon2.softax.pl> <fhv020$8k1$1@news.vectranet.pl> <fi1bs4$nn3$1@bozon2.softax.pl> <fi27ds$gt1$1@kujawiak.man.lodz.pl> <1195688300.8426.30.camel@qrnik> <fi3ems$7ig$1@kujawiak.man.lodz.pl> <1195734091.8426.77.camel@qrnik> <fi6n5f$fpr$1@kujawiak.man.lodz.pl> <1195858230.20523.107.camel@qrnik> <fie2un$cbn$1@kujawiak.man.lodz.pl> <1196076390.30869.52.camel@qrnik> <fj1tmo$52u$1@kujawiak.man.lodz.pl> <1101d6ea-b312-4214-b153-8e1cc26a99ba@n20g2000hsh.googlegroups.com>
NNTP-Posting-Host: student.kis.p.lodz.pl
Mime-Version: 1.0
X-Trace: kujawiak.man.lodz.pl 1196862252 942 212.191.89.21 (5 Dec 2007 13:44:12 GMT)
X-Complaints-To: abuse@man.lodz.pl
NNTP-Posting-Date: Wed, 5 Dec 2007 13:44:12 +0000 (UTC)
User-Agent: tin/1.8.3-20070201 ("Scotasay") (UNIX) (FreeBSD/6.2-RELEASE-p3 (sparc64))
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit