wyjątki c++

EM
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 10 lat
  • Postów:271
0

cześć, w nauce c++ doszedłem do wyjątków i mam kilka pytań a dokładniej nie rozumiem do końca kiedy je stosować? czy są operacje w których jasno określone jest że, używając ich (tych operacji/funkcji) musimy użyć wyjątku? Jako przykład (nie wiem czy dobry) podam operator indeksowania [] dla klasy "bezpiecznej tablicy"
kod z obsługą wyjątku

Kopiuj
int operator[] (int x)
        {
            try {
                if (x >= indeks) {
                    throw out_of_range("blad zakresu tablicy");
                }

                return tab[x];
            }

            catch(logic_error & e) {
                cout<< "wylapany wyjatek logic_error" <<endl;
                cout<< e.what() <<endl;
                return tab[indeks-1];
            }
        }

i bez wyjątku

Kopiuj
int operator[] (int x)
        {
            if (x >= indeks) {
                cout<< "blad zakresu tablicy" <<endl;
                return tab[indeks-1];
            }

            return tab[x];
        }

Czytałem też, że wyjątki mają negatywny wpływ na wydajność programu wiec jak to jest z ich stosowaniem? Czy jeżeli możemy dana sytuacje obsłużyć/zabezpieczyć w inny sposób to znaczy że wyjątek nie jest potrzebny? Z tym że w bardzo wielu przypadkach można wykorzystać zwykła klasę z numerem błędu i np stringiem informującym co poszło nie tak? Proszę o krótkie wytłumaczenie tej kwestii

edytowany 1x, ostatnio: emacs
fasadin
  • Rejestracja:prawie 14 lat
  • Ostatnio:prawie 3 lata
  • Postów:4882
1

wyjątek. Czyli sytuacja wyjątkowa. Na przykład operator new wyrzuci Ci wyjątkiem jeżeli nie uda mu się stworzyć obiektu.
Ty np pisząc funkcje która coś zapisuję do pliku możesz śmiało użyć wyjątków? Dlaczego? Bo nie jesteś w stanie przewidzieć wszystkich opcji. (brak uprawnień do zapisu, brak miejsca na dysku, zła nazwa pliku itd). Jeżeli co kolwiek się źle powiedzie rzucasz wyjątkiem. Po co? Jak ktoś w przyszłości będzie korzystał z Twojej funkcji zapiszDoPliku będzie mógł złapać ten wyjątek i odpowiednio go obsłużyć.

Ogólnie dzięki wyjątkom program się nie crashuje (jeżeli wyjątek złapiesz) i zamiast crashu możesz coś poczynić jeżeli sytuacja wyjątkowa nastąpiła

dla operatora [] przy bezpieczniej tablicy wyjątek jest jak najbardziej na miejscu

ja korzystając z "BezpiecznejTablicy" cieszyłbym się jakby mi klasa rzucała wyjątkami jeżeli przekroczę indeks (żebym czasem nie mazał po nie swojej pamięci)

edytowany 2x, ostatnio: fasadin
EM
dziękuje za odpowiedź, ale w takim razie wytłumacz mi w czym gorsza jest obsługa tego operatora[] w przykładzie bez wyjątku? zwykły if w tym przypadku również zabezpiecza program i obsługuje sytuacje która może powodować błąd, a przy tym w przypadku wystąpienia takiej sytuacji jest szybsza?
fasadin
jeżeli udostępnisz tą klasę żeby każdy mógł z niej skorzystać to powinieneś po prostu wyrzucić wyjątek (i go nie łapać) tak by korzystający z klasy sam sobie go obsłużył (akuratnie tutaj wystarczy sam if [chociaż zależy od sytuacji], ale staram się bardziej uzmysłowić do czego mogą się przydać wyjątki)
n0name_l
  • Rejestracja:ponad 12 lat
  • Ostatnio:prawie 5 lat
  • Postów:2412
1

Wyjatki sie stosuje w sytuacjach, kiedy cos MOZE pojsc nie tak nie z naszej winy. Genialnym przykladem jest alokacja pamieci ;)
Do sprawdzania danych wejsciowych czy wyjsciowych funkcji zazwyczaj uzywa sie asercji lub tego typu mechanizmow.
Co do tego co przedstawiles to MOZESZ, ale nie MUSISZ masz wolna reke, w wiekszosci przypadkow da sie uniknac stosowania wyjatkow.
btw. bledny warunek wstawiles tak czy siak.

EM
dlaczego błędny? indeks to zmienna int w klasie która zawiera rozmiar tablicy
n0name_l
przetestuj dla x = -1
EM
no tak, wartości ujemnych nie brałem w ogóle pod uwage ;)
_13th_Dragon
  • Rejestracja:prawie 20 lat
  • Ostatnio:14 dni
1

Wersja z wyjątkami jest nieporozumieniem, powinno to wyglądać tak:

Kopiuj
int operator[] (size_t x)
  {
   if(x>=indeks) throw out_of_range("blad zakresu tablicy");
   return tab[x];
  }

Np masz funkcje:

Kopiuj
int suma(Tablica &T)
  {
   int s=0;
   for(i=0;i<T.size();--i) s+=T[i]; // tu "niezamierzony" błąd jest --i zamiast ++i
   return s;
  }

Oraz jej wywołanie:

Kopiuj
Tablica T(20);
try
  {
   cout<<suma(T)<<endl;
  }
catch(...)
  {
   cout<<"Coś sknociłeś w funkcji suma"<<endl;
  }

Owszem reakcja na wyjątek jest strasznie powolna, ale wyjątki to wyjątkowe sytuacje które nie powinny się zdarzać.


Wykonuję programy na zamówienie, pisać na Priv.
Asm/C/C++/Pascal/Delphi/Java/C#/PHP/JS oraz inne języki.
edytowany 1x, ostatnio: _13th_Dragon
robcio
  • Rejestracja:prawie 13 lat
  • Ostatnio:ponad 10 lat
  • Lokalizacja:Opole
  • Postów:533
0

Wyjątki są przydatne jak np wywołujemy dużo funkcji które rzucają ten sam typ wyjątku. Możemy w jednym miejscu umieścić blok catch i wszystkie wyjątki jednego typu zostaną przechwycone. Jak byśmy używali sprawdzania znacznika błędu kod byłby dość nieczytelny bo za każdym razem musielibyśmy sprawdzać ifem czy nie nastąpił błąd.


Nie odpowiadam na PW z prośbą o pomoc programistyczną.
edytowany 1x, ostatnio: robcio
matek3005
  • Rejestracja:około 15 lat
  • Ostatnio:prawie 5 lat
  • Postów:358
1

no tak, wartości ujemnych nie brałem w ogóle pod uwage ;)
i słusznie, że nie brałeś ich pod uwagę (w warunku) bo indeks tablicy nie powinien być liczbą ujemną. Niesłuszne jest natomiast to, że do indeksowania tablicy stosujesz typ, który przechowuje wartości ujemne.
Użycie wyjątków np. przy indeskowaniu klas implementujących tablice jest wg mnie śmieszne bo jest to idotoodporność dla programisty, która sporo kosztuje. Programista sam powinien dbać o to aby nie przekroczyć zakresu dlatego stosowanie wyjątków w sytuacjach błędów logicznych programisty jest zbędne z perspektywy projektanta klasy. Taką koncepcje obrali również twórcy biblioteki standardowej c++ (w tym stl'a), która posiada znikomą obsługę błędów (chroni przede wszystkim przed błędami wykonania spowodowanymi przez środowisko wykonania programu bądź jego kontekst, czyli takimi, na które programista nie ma bezpośredniego wpływu). Oczywiście istnieją wersje biblioteki standardowej z obsługą błędów ale te dołączone do popularnych kompilatorów najczęściej jej nie posiadają - i słusznie. Gdy chcesz kontroli w określonym przypadku sam możesz ją zaimplementować opakowując odpowiednio w klasę elementy, które chcesz nadzorować.

edytowany 3x, ostatnio: matek3005
EM
od początku byłem zdziwiony, że w c++ tak 'łatwo' można przekroczyć zakres tablicy (co przy implementacji różnego rodzaju algorytmów opartych właśnie na tablicach zdarzało się, zdarza i będzie zdarzać) i nikt nie protestuje....kompilatory (bo to chyba ich zadanie?) obsługują o wiele bardziej złożone mechanizmy wiec nie rozumiem dlaczego pominięto tak podstawową opcje jak test zakresu tablicy i stąd moja chęć do napisania klasy 'bezpiecznej tablicy' a że zbiegło się to z nauką wyjątków które chciałem zastosować dlatego ten post ;)

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.