Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Poprzednia wersja
Nowa wersja
Poprzednia wersja
pl:dydaktyka:jimp2:2017:labs:wyjatki [2017/04/25 04:08]
mwp [Podstawy obsługi wyjątków]
pl:dydaktyka:jimp2:2017:labs:wyjatki [2019/06/27 15:50] (aktualna)
Linia 152: Linia 152:
  
 {{.:​exceptions.png |Zwijanie stosu}}<​code cpp> {{.:​exceptions.png |Zwijanie stosu}}<​code cpp>
-int foo() throw (exception) {+int foo() {
   string s("ala ma kota"​);​   string s("ala ma kota"​);​
   bar();   bar();
Linia 158: Linia 158:
 } }
  
-int bar() throw (exception){+int bar() {
   // pamięć nie    // pamięć nie 
   // zostanie zwolniona   // zostanie zwolniona
Linia 166: Linia 166:
 } }
  
-int fido() throw (exception){+int fido() {
   Matrix m("[1 2 3; 3 4 5]");   Matrix m("[1 2 3; 3 4 5]");
-  throw exception();+  throw runtime_error(__func__ + " error in " + __FILE__ + " at " + __LINE__);
   return 0;   return 0;
 } }
Linia 177: Linia 177:
     foo();     foo();
  
-  }catch(exception e){}+  } catch(const exception ​&e){ 
 +    cerr << e.what() << endl; 
 +  ​}
  
   cout << "​Dalej"​ << endl;   cout << "​Dalej"​ << endl;
Linia 191: Linia 193:
 using namespace std; using namespace std;
  
-Matrix Matrix::​div(const Matrix& m) throw (WrongDimensionException,​ DivisionByZero){+Matrix Matrix::​div(const Matrix& m) {
   // jeśli wymiary nie są prawidłowe,​ to zgłoś wyjątek   // jeśli wymiary nie są prawidłowe,​ to zgłoś wyjątek
  
Linia 201: Linia 203:
 } }
 </​code>​ </​code>​
- 
- 
 =====Przechwycenie wyjątku===== =====Przechwycenie wyjątku=====
 ====try/​catch==== ====try/​catch====
Linia 233: Linia 233:
 Oznacza on mniej więcej tyle: //jeśli pojawił się wyjątek, którego nie mają w parametrach wcześniejsze bloki catch ja się nim zajmę.// **Uwaga** Kolejność bloków catch ma znaczenie! Konstrukcja //​catch(...)//​ pasuje do wszystkich wyjątków, dlatego powinna być umieszczana zawsze jako ostatnia. Oznacza on mniej więcej tyle: //jeśli pojawił się wyjątek, którego nie mają w parametrach wcześniejsze bloki catch ja się nim zajmę.// **Uwaga** Kolejność bloków catch ma znaczenie! Konstrukcja //​catch(...)//​ pasuje do wszystkich wyjątków, dlatego powinna być umieszczana zawsze jako ostatnia.
  
 +
 +Jeśli dwa różne wyjątki mają wspólną klasę bazową można je przechwycić w pojedynczym bloku catch:
 +<code cpp>
 +int main() {
 +  Matrix m1 ...
 +  Matrix m2 ...
 +  try {
 +     ​m1.div(m2);​
 +  } catch (const invalid_argument &e) {
 +     cerr << e.what() << endl;
 +  } catch (...) {
 +     //ten blok jest wstanie przechwycić każdy inny wyjątek
 +     cerr << "​Something went wrong" << endl;
 +  }
 +}
 +</​code>​
 ====Wyjątki nieoczekiwane==== ====Wyjątki nieoczekiwane====
 W przypadku kiedy wewnątrz funkcji pojawi się wyjątek, który nie znajduje się w specyfikacji wyjątków danej funkcji, wywoływana jest automatycznie funkcja //​unexpected//,​ która z kolei wywołuje funkcje ustawioną przez //​set_unexpected//​. Domyślnie funkcją tą jest //​terminate//​ - czyli zakończenie programu. ​ W przypadku kiedy wewnątrz funkcji pojawi się wyjątek, który nie znajduje się w specyfikacji wyjątków danej funkcji, wywoływana jest automatycznie funkcja //​unexpected//,​ która z kolei wywołuje funkcje ustawioną przez //​set_unexpected//​. Domyślnie funkcją tą jest //​terminate//​ - czyli zakończenie programu. ​
Linia 267: Linia 283:
 Jeśli zdefiniowana przez programistę funkcja nie rzuca wyjątku określonego w specyfikacji funkcji (patrz [[#​specyfikacja_wyjatkow|Specyfikacji wyjątków]],​ to program po jej wywołaniu i tak zostanie zakończony. Jeśli zdefiniowana przez programistę funkcja nie rzuca wyjątku określonego w specyfikacji funkcji (patrz [[#​specyfikacja_wyjatkow|Specyfikacji wyjątków]],​ to program po jej wywołaniu i tak zostanie zakończony.
  
-=====Specyfikacja wyjątków===== +=====noexcept===== 
-//Specyfikacja ​wyjątków// ​pozwala na zdefiniowanie listy wyjątków, ​które mogą być zgłoszone przez funkcję. Robi się to przy pomocy operatora //throw// umieszczonego po liście parametrów funkcji+Specyfikacja ​noexcept ​pozwala na jawne zadeklarowanie metody jako nie wyrzucającej ​wyjątków, ​wtedy żadna pochodna metoda również nie może wyrzucać wyjątków, wszystkie pozozstałe motedy są traktowane jako potencjlanie wyrzucające wyjątki
  
 <code cpp> <code cpp>
Linia 282: Linia 298:
   public:   public:
     ...     ...
-    // Metoda ​może zgłosić ejden z dwóch ​wyjątków określonych +    // Metoda ​potencjalnie wyrzuca ​wyjątki 
-    ​// jako parametry operatora throw. Zakładamy, ze klasy +    ​Matrix div(const Matrix&​);​ 
-    // WrongDimensionsExcpetion i DivisionByZero są zaimplementowane +    // Metoda nie może wyrzucić wyjątku 
-    Matrix ​div(const Matrix&​) throw (WrongDimensionsExcpetion,​DivisionByZero);+    ​virtual ~Matrix() ​noexcept;
 }; };
  
 </​code>​ </​code>​
- 
-Umieszczenie pustej specyfikacji wyjątków (throw()) oznacza, ze funkcja nie powinna zgłaszać żadnych wyjątków. Jeśli jednak wewnątrz funkcji zostanie zgłoszony wyjątek, zostanie wywołana funkcja //​unexpected//​. Jeśli nie określi się żadnych wyjątków, to znaczy, że metoda może zgłaszać dowolne wyjątki. 
- 
-<code cpp> 
-int myfoo (int param) throw(); // nie można zgłaszać żądnych wyjątków 
-int mybar (int param); ​        // wszystkie wyjątki dozwolone 
-</​code>​ 
- 
 =====Konstruktory,​ destruktory i wyjątki===== =====Konstruktory,​ destruktory i wyjątki=====
  
Linia 304: Linia 312:
 Wyjątki w konstruktorach wyrzuca się w analogiczny sposób jak w //​zwykłych//​ metodach. Kiedy zostanie wyrzucony wyjątek w ciele konstruktora,​ mechanizm zwijający stos uruchomi destruktory wszystkich obiektów składowych danego obiektu. ​ Wyjątki w konstruktorach wyrzuca się w analogiczny sposób jak w //​zwykłych//​ metodach. Kiedy zostanie wyrzucony wyjątek w ciele konstruktora,​ mechanizm zwijający stos uruchomi destruktory wszystkich obiektów składowych danego obiektu. ​
  
-Problem pojawia się jednak kiedy w ciele konstruktora dynamicznie alokujemy pamięć. Nie zostanie ona w takim wypadku zwolniona.+W praktyce zawsze należy sprwdzić dziedzinę parametrów przekazanych w konstruktorze i pozowalać na utworzenie jedynie w pełni poprawnego obiektu, namtomiast w przeciwnym wypadku należy wyrzucić wyjątek. 
 + 
 +Problem pojawia się jednak kiedy w ciele konstruktora dynamicznie alokujemy pamięć. Nie zostanie ona w takim wypadku zwolniona. Chyba, że użyjemy smart pointery
  
 ====Wyjątki w destruktorze==== ====Wyjątki w destruktorze====
Linia 312: Linia 322:
 C++ gwarantuje co prawda, że w przypadku zaistnienia takiej sytuacji zostanie wywołana funkcja //​terminate()//​ i program zostanie zamknięty, nie jest to jednak satysfakcjonujące rozwiązanie. C++ gwarantuje co prawda, że w przypadku zaistnienia takiej sytuacji zostanie wywołana funkcja //​terminate()//​ i program zostanie zamknięty, nie jest to jednak satysfakcjonujące rozwiązanie.
  
 +Od wersji C++11 destuktory domyślnie są zadeklarowane jako noexcept.
 =====Dziedziczenie i wyjątki===== =====Dziedziczenie i wyjątki=====
 (:!: do zrozumienia tej sekcji wymagana jest znajomość mechanizmu dziedziczenia w C%%++%% -> laboratorium [[.:​dziedziczenie|Dziedziczenie i polimorfizm]]) (:!: do zrozumienia tej sekcji wymagana jest znajomość mechanizmu dziedziczenia w C%%++%% -> laboratorium [[.:​dziedziczenie|Dziedziczenie i polimorfizm]])
Linia 332: Linia 343:
 }; };
  
-void drawBall() throw (BallException){+void drawBall() {
   throw BallException();​   throw BallException();​
 } }
Linia 348: Linia 359:
  
 Już podczas kompilacji otrzymujemy ostrzeżenie,​ że wyjątek //​BallException//​ nigdy nie zostanie wychwycony. Dzieje się tak dlatego, że po napotkaniu pierwszego bloku //catch//, nastąpi automatyczne rzutowanie w górę i dopasowanie //​BallException//​ do //​CircleException//​. ​ Już podczas kompilacji otrzymujemy ostrzeżenie,​ że wyjątek //​BallException//​ nigdy nie zostanie wychwycony. Dzieje się tak dlatego, że po napotkaniu pierwszego bloku //catch//, nastąpi automatyczne rzutowanie w górę i dopasowanie //​BallException//​ do //​CircleException//​. ​
 +
 +===== Warto się zapoznać =====
 +  - [[http://​www.exceptionsafecode.com/​]] (filmiki z konferencji)
 +  - [[http://​en.cppreference.com/​w/​cpp/​language/​noexcept_spec]]
 +  - [[http://​www.gotw.ca/​publications/​mill22.htm]]
  
 ======Ćwiczenia====== ======Ćwiczenia======
-  - Przetestuj przykład z sekcji [[#​dziedziczenie_i_wyjatki|Dziedziczenie i wyjątki]]. Co zrobić, żeby wyjątek //​BallException//​ był łapany poprawnie?​ +  - [1 plus] Przetestuj przykład z sekcji [[#​dziedziczenie_i_wyjatki|Dziedziczenie i wyjątki]]. Co zrobić, żeby wyjątek //​BallException//​ był łapany poprawnie?​ 
-  - Napisz trzy metody, które będą posiadały wyspecyfkowane po jednym wyjątku jaki mogą wyrzucać. W każdej z metod wyrzuć wyjątek, ale inny od tego jaki został wyspecyfikowany. Za pomocą //​set_unexpected//​ ustaw metodę, która będzie uruchamiana w takim wypadku. **Uwaga**: Program nie może się zakończyć w przypadku wywołania żadnej z funkcji! Jak to osiągnąć pisząc tylko jedną funkcję //​unexpected//​ i pamiętając,​ że program nie zostanie zatrzymany tylko wtedy kiedy funkcja //​unexpected//​ wyrzuci wyjątek określony w specyfikacji funkcji, która wyrzuciła niepoprawny wyjątek? +  - [plusy] ​Napisz klasę //PESEL//, która w konstruktorze przyjmuje ciąg znaków będących numerem PESEL. Klasa powinna posiadać metodę //​validatePESEL(const char*)//, która sprawdza czy PESEL jest poprawny według algorytmu podanego na [[http://​pl.wikipedia.org/​wiki/​PESEL|Wikipedii]]. Jeśli przekazany do konstruktora PESEL nie jest poprawny, program powinien wyrzucać wyjątek. Napisz funkcję //main// i przetestuj program. 
-  - Napisz klasę //PESEL//, która w konstruktorze przyjmuje ciąg znaków będących numerem PESEL. Klasa powinna posiadać metodę //​validatePESEL(const char*)//, która sprawdza czy PESEL jest poprawny według algorytmu podanego na [[http://​pl.wikipedia.org/​wiki/​PESEL|Wikipedii]]. Jeśli przekazany do konstruktora PESEL nie jest poprawny, program powinien wyrzucać wyjątek. Napisz funkcję //main// i przetestuj program. +  - [3 plusy] Dla klasy Student dopisać metody walidujące argumenty przekazywane do klasy. W taki sposób by uniemożliwić storzenie niepoprawnego stanu obiektu.  
-  - Napisz program, który będzie służył do opóźniania,​ lub przyspieszania wyświetlania napisów do filmów w formacie ​MicroDVD ​;-)Czas pojawienia się napisu oznaczany ​jest w tym formacie dwiema liczbami umieszczonymi pomiędzy nawiasami klamrowymi. Pierwsza liczba to numer klatki pojawienia się napisu, druga to numer klatki zniknięcia. Program powinien posiadać metodę //delay(const char* in, const char* out,int delay, int fps)// wykonującą opóźnienie (lub przyspieszenie) napisów o podaną ilość milisekund w zależności od tego jaki film ma //framerate//. \\ Program powinien przyjmować jako parametry cztery wartościścieżkę do pliku wejściowego, ścieżkę do pliku wyjściowego ​liczbę milisekund i //​framerate//​. ​ Metoda //delay// powinna ​wyrzucać wyjątek gdy w pliku pojawi ​się niepoprana sekwencja znakówNp. zamiast ​{1234}{4565} pojawia się {sdfg}{33ff}. +    * Student musi mieć co najmniej imię i nazwisko, każdy człon imienia musi być napisany z wielkiej litery pozostałe litery małe. Imię nie może zawierać cyfr i znaków specjalnych (amperad, dolar, procent, itp...) 
-  - Jeśli masz dostępną swoją klasę Matrix ​(laboratorium [[.:klasy2|Klasy ​obiekty II]]), dopisz dla niej obsługę wyjątków+    * Wiek studenta musi mieścić się w zakresie 10 do 100 lat 
 +    * kierunek studiów musi zawierać się w zbiorze oferowanym akutalnie przez uczelnie XYZ: informatyka,​ ekonomia, matematyka, fizyka, filozofia 
 +    * w każdym wypadku, kiedy zostanie naruszony któryś z warunków należy zwrócić wyjątek dziedziczący po klasie invalid_argument,​ odpowiednio:​ 
 +      * InvalidNameSurname,​ InvalidNameCharacters, ​ InvalidAge, InvalidProgram 
 +    * dopisać main z możliwością wczytywania danych o studencie i tworzącym studentów w pętli wstawiającym poprawnie utworzone obiekty do repozytorium. 
 + 
 +======Zadanie domowe====== 
 +Napisz program, który będzie służył do opóźniania,​ lub przyspieszania wyświetlania napisów do filmów w dwóch różnych formatach: ​MicroDVD ​i SubRipElementem centralnym interfejsu biblioteki ​jest abstrakcyjna klasa: **MovieSubtitles** z dwoma wirtualnymi metodami ​(przestrzeń nazw **moviesubs**):​  
 +    * <code cpp>void ShiftAllSubtitlesBy(int offset_in_micro_seconds,​ int frame_per_second,​ std::​istream ​*in, std::​ostream ​*out)</code> - metoda nie powinna posiadać domyślnej implementacji (abstrakcyjna,​ czysto wirtualna). 
 +    * Destruktor (domyślna implementacja) 
 +  - **[1 punkt]** (lab8_micro_dvd_correct_cases_tests) Zaimplementuj klasę **MicroDvdSubtitles** implementującą metody z klasy bazowej **MovieSubtitles** i wspierającą format **MicroDvd**. Każda linia ma następujący format: ​//{INT_ON}{INT_OFF}SUBTITLE// gdzie nawiasy klamrowe wystepują w tej linii jak widać, natomiast INT_ON oznacza numer klatki filmu, w której pojawia się napis; INT_OFF numer klatki filmu w której znika napis; SUBTITLE oznacza napis do wyświetleniaW tym formacie napis do wyświetlenia może zawierać dodatkowe informacje sterujące wyświetlaniem, np. | rozdzielający linie napisu, czy {y:b} wprowadzający pogrubienie.  
 +  - **[1 punkt]** (lab8_micro_dvd_error_cases_tests) Przesuwanie napisów powinno również obsługiwać przypadki, gdy podany plik (zawrtość strumienia ​wejściowego) zawiera niepoprawnie sformatowany tekst: 
 +    * próba przesunięcia klatek wstecz która skutkowałaby ujemnymi wartościami INT_ON ​i/lub INT_OFF ​powinna ​być zasygnalizowana przez wyjątkiem **NegativeFrameAfterShift** 
 +    * jeśli klatka ma zniknąć przed pojawieniem ​się (INT_ON >= INT_OFF) należy zasygnalizować to wyjątkiem **SubtitleEndBeforeStart** 
 +    * jeżeli jest inny błąd formatowania lini npbrak {INT_OFF}, brak nawiasu klamrowego, itpnależy zwrócić wyjątek **InvalidSubtitleLineFormat** 
 +    * jeżeli kolejne napisy pojawiają sie przed niż wcześniejszymi napisami powinine zostać zgłoszony wyjątek **OutOfOrderFrames** 
 +    * wszystkie te wyjątki powinny dziedziczyć po klasie **SubtitlesException**,​ która przyjmuje dwa argumenty w konstruktorze:​ numer linii, w której wystąpił błąd, treść tej linii (cała linia, nie tylko etykieta). A z kolei klasa **SubtitlesException** powinna dziedziczyć po klasie **std::​invalid_argument** z biblioteki stdexcept 
 +  - **[1 punkt]** (lab8_sub_rip_correct_cases_tests) Zaimplementuj klasę **SubRipSubtitles** implementującą metody z klasy bazowej **MovieSubtitles** i wspierającą format **SubRip**Każda napis ma następujący format//INDEX NEW_LINE TIME_IN -> TIME_OFF NEW_LINE SUBTITLE1 NEW_LINE SUBTITLE2 NEW_LINE NEW_LINE//, gdzie INDEX - to numer klatki, NEW_LINE to znak nowej linii, TIME_IN ​TIME_OFF to moment pojawienia się i zniknięcia klatki w formacie HH:​MM:​SS,​mmm (godzina:​minuta:​sekundy,​milisekundy). Napisy mogą być wielolinijkowenowa klatka pojawia się po pustej linii. 
 +  - **[1 punkt]** (lab8_sub_rip_error_cases_tests) poza wyjątkami wymienionymi w punkcie drugim należy zaimplementować też: 
 +    * numery klatek są nie pokolei **OutOfOrderFrames**  
 +    * jeśli klatka nie posiada secyfikacji kiedy miałaby się pojawić **MissingTimeSpecification** 
 +  - **[1 punkt]** (lab8_movie_subtitles_tests) sprawdzić czy wszystko działa ok
pl/dydaktyka/jimp2/2017/labs/wyjatki.1493086089.txt.gz · ostatnio zmienione: 2019/06/27 15:52 (edycja zewnętrzna)
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0