znaczacy > comp.lang.* > comp.lang.c

SasQ (06.07.2008, 18:53)
Siema.

Czesto w róznych jezykach majacych mechanizm wyjatków
napotykam na pewien problem, z którym jak dotad sobie
nie poradzilem. Moze ktos z Was bedzie wiedzial, jak
to rozegrac? Chodzi o taka sytuacje:

W bloku try wykonuje jakies operacje, które czasami moga
sie nie udac. Ale zazwyczaj sie udaja i kod jest zbudowany
tak, jakby zawsze sie udawaly.
Gdy jednak cos pójdzie nie tak, rzucany jest odpowiedni
wyjatek [moze ich byc wiele róznych, zaleznie od tego,
co sie nie udalo].
Pod calym tym blokiem kodu w try jest oczywiscie seria
bloków catch, które obsluguja te wyjatki.

Niekiedy w takiej obsludze istnieje mozliwosc naprawy
problemu i w takiej sytuacji chcialbym jakims sposobem
ponownie wywolac blok try, by jeszcze raz spróbowac.
Dlaczego?
Poniewaz kod zawarty w tym bloku [niekoniecznie na wierzchu,
moze byc gdzies zakopany na któryms poziomie wywolania funkcji]
odpowiada za sprawdzanie tych danych i rzuca wyjatki w przypadku
ich nieprawidlowosci, lub gdy czegos nie moze zrobic. Chce
wiec ponownie uzyc tego kodu, niech jeszcze raz zrobi swoje i
sprawdzi nowe dane - moze po poprawieniu w catch sa juz poprawne.
Czyli wyglada to mniej wiecej tak:

try {
//bla bla bla
sprobujZrobicCoTrzeba(dane);
//Powyzsza funkcja gdzies w swoich bebechach sprawdza,
//czy dane sa poprawne. Gdy sa niepoprawne, rzuca
//odpowiedni do sytuacji wyjatek. Moze tez rzucac inne
//wyjatki, gdy cos sie nie uda [np. otwarcie pliku,
//dostep do bazy danych itp.]
}
//A tu obsluga jednego z tych wyjatków niepoprawnych danych:
catch (EBadData_WrongDickSize& e)
{
//Poprawiamy dane.
enlargeDick(2);
//Dane poprawione. Jak teraz spróbowac ponownie? :|
}

No wlasnie :P Co zrobic, zeby jeszcze raz wywolac teraz kod
zawarty w poprzedzajacym bloku try, by mógl sprawdzic dane
jeszcze raz i gdy beda OK, zrobic co trzeba, a gdy nie beda,
jeszcze raz rzucic wyjatkiem? [Warto zauwazyc, ze dane moga byc
niepoprawne tym razem z innego powodu.]
Gdy napotykam taki kod, zazwyczaj pierwszym odruchem jest
sklecenie czegos takiego:

try {
//bla bla bla
sprobujZrobicCoTrzeba(dane);
}
catch (EBadData_WrongDickSize& e)
{
enlargeDick(2);
sprobujZrobicCoTrzeba(dane);
}

i teraz wracamy do punktu wyjscia: drugie wywolanie funkcji
musi byc znów opakowane w blok try :P

try {
//bla bla bla
sprobujZrobicCoTrzeba(dane);
}
catch (EBadData_WrongDickSize& e)
{
enlargeDick(2);
try {
sprobujZrobicCoTrzeba(dane);
}
//tu ponownie cala seria bloków catch? ta sama?!
}

Nieee :P Od razu widac, ze cos tu jest nie tak.
Kod zaczyna sie dublowac, a to wyraznie wskazuje, ze
cos robie nie tak. Tylko co? I jak to zrobic dobrze?
Czy istnieje jakis sposób/konstrukcja/whatever, która
umozliwilaby powrót jeszcze raz do bloku try?
Wojciech Muła (06.07.2008, 20:47)
On Sun, 6 Jul 2008 16:53:04 +0000 (UTC) SasQ <sasq1> wrote:

> Siema.
> Często w różnych językach mających mechanizm wyjątków
> napotykam na pewien problem, z którym jak dotąd sobie
> nie poradziłem. Może ktoś z Was będzie wiedział, jak
> to rozegrać? Chodzi o taką sytuację:
> [...]


Rzadko mi się taki kod zdarza, ale jak już, to piszę mniej
więcej tak:

try {
while (not ok) {
try {
operacja którą można wołać parę razy
ok = true;
}
catch (wyjątki, przy których można naprawić sytuację) {
kod poprawiający
}
}
}
catch (wyjątki bez rokowań na poprawę) {
coś tam
}

w.
Sebastian Kaliszewski (07.07.2008, 14:10)
Wojciech Muła wrote:
[..]
> catch (wyjątki bez rokowań na poprawę) {
> coś tam
> }


Ewentualnie tak (ma zaletę taką, że w obsłudze wyjątku jawnie ustawia się
konieczność powtórki, i można to nawet zrobić zależnie od aktualnej
dynamicznej sytuacji, np. liczby powtórzeń):

bool repeat = false;
do
{
try
{
operacja którą można powtórzyć
}
catch(wyjątki wszelkie)
{
obsługa wyjątków
jeśli ma być powtórzenie to
{
repeat = true;
}
}
} while(repeat);

pzdr
Daniel Janus (07.07.2008, 15:55)
Dnia 06.07.2008 SasQ <sasq1> napisał/a:

> Czy istnieje jakiś sposób/konstrukcja/whatever, która
> umożliwiłaby powrót jeszcze raz do bloku try?


Z cyklu ,,jak to robią inne języki'' (tak, jestem ostatnimi czasy
offtopicznie monotematyczny...):

Mis Uszatek (07.07.2008, 20:11)
On 2008-07-06, Wojciech Mula <wojciech_mula> wrote:
[..]
> catch (wyjatki bez rokowan na poprawe) {
> cos tam
> }


Tez uzywam takiej konstrukcji, jednak czasami lepiej by bylo nie
rozpoczynac od nowa bloku try, a wskoczyc w miejsce skad rzucono wyjatek.
Czy to ze wzgledu na koszty ponownych wywolan, czy ze wzgledu na efekty
uboczne. Mozna zrobic to w taki sposób:

int i = 1;

while (i != 0) {
try {
if (i <= 1) {
if (warunek1)
throw Wyjatek1;

f1();
f2();
}

if (i <= 2) {
if (warunek2)
throw Wyjatek2;

f3();
}

i = 0;
}

catch (Wyjatek1&) {
// ...
i = 1;
}

catch (Wyjatek2&) {
// ...
i = 2;
}
}

Nie jest to jednak zbyt eleganckie rozwiazanie. Pytanie czy istnieje lepsze?

Pozdrawiam,
Uszatek.
Podobne wątki