vypracovani temat z 3. prednasky
This commit is contained in:
85
3. týden.md
Normal file
85
3. týden.md
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
s- výjimky
|
||||||
|
- reference
|
||||||
|
- konstantní metody/atributy
|
||||||
|
- přetížené operátory
|
||||||
|
- indexování + volání funkce (oboje jsou operátory)
|
||||||
|
- lambda funkce
|
||||||
|
|
||||||
|
- cvičení
|
||||||
|
- conteinery: vector, list, mapa
|
||||||
|
-
|
||||||
|
# Výjimky
|
||||||
|
- Pozn: "Častokrát je možná lepší, když ten program spadne, než když se chová špatně."
|
||||||
|
- Řešení neočekávaných chyb
|
||||||
|
- Může se to stát náhodně (např. poškozený/přeplněná paměť)
|
||||||
|
- používá se **try** a **catch**
|
||||||
|
```
|
||||||
|
try {
|
||||||
|
# kod kde nastane vyjimka / problem
|
||||||
|
}
|
||||||
|
catch (typ vyjimky) {
|
||||||
|
# kod, ktery se s vyjimkou popasuje
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
knihovna: `#include <exception>`
|
||||||
|
Pak existuje ještě třetí operátor a to operátor `throw`, který vyvolává výjimku.
|
||||||
|
např `throw "Deleni nulou.\n` -> vyvolá výjimku **Deleni nulou\n**
|
||||||
|
``
|
||||||
|
## Ošetření více výjimek
|
||||||
|
```
|
||||||
|
catch (typ vyjimky) {
|
||||||
|
# kod, ktery se s vyjimkou popasuje
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
# univerzalni reseni vyjimek pro vsechno ostatní
|
||||||
|
}
|
||||||
|
```
|
||||||
|
## Typy výjimek
|
||||||
|
- `<exceptions>`
|
||||||
|
- `std::exception` - bázová třída
|
||||||
|
- `virtual what()` - vrací řetězec výjimky
|
||||||
|
- `terminate()` - ukončí program, když se něco pokazí?
|
||||||
|
- `<stdexcept>`
|
||||||
|
- `std::out_of_range`
|
||||||
|
- nestihl
|
||||||
|
- nestihl
|
||||||
|
- `<new>`
|
||||||
|
- nestihl
|
||||||
|
- nestihl
|
||||||
|
|
||||||
|
# Reference
|
||||||
|
- ukazatelé byly označeny komunitou C++ jako nebezpečné např. kvůli nejasné syntaxi
|
||||||
|
- Reference je obdoba konstantního ukazatele
|
||||||
|
- nelze vytvořit prázdnou referenci, je svázána s hodnotou a ne adresou (?)
|
||||||
|
- Pokud možno **pls používat reference**
|
||||||
|
|
||||||
|
- Reference
|
||||||
|
# Přetížené operátory
|
||||||
|
- stejně jako funkce lze přetížit operátory (protože to jsou vlastně takové funkce)
|
||||||
|
|
||||||
|
- operátory definované pro dané datové typ nelze přetížit
|
||||||
|
- týká se to hlavně operátorů pro instance tříd
|
||||||
|
- např nelze přetížit: `.` `.*` `::` `?:` `sizeof`
|
||||||
|
|
||||||
|
## Přetížení binárních operátorů
|
||||||
|
např: `+, -, *, ..., +=, -=, ...`
|
||||||
|
používá se `@`
|
||||||
|
např: `x @ y`
|
||||||
|
|
||||||
|
## Přetížení unárních operátorů
|
||||||
|
|
||||||
|
## Přetížení postfixových operátorů
|
||||||
|
# Lambda funkce
|
||||||
|
|
||||||
|
- existuje něco jako funktor :C
|
||||||
|
- místo funktoru mám lambda funkce
|
||||||
|
- každou lambda funkci můžu přepsat do funktoru
|
||||||
|
|
||||||
|
# Conteinery
|
||||||
|
|
||||||
|
## Vector
|
||||||
|
|
||||||
|
## List
|
||||||
|
|
||||||
|
## Map
|
||||||
74
Funktory a Lambda funkce.md
Normal file
74
Funktory a Lambda funkce.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Funktory
|
||||||
|
Jsem línej to víc rozepsat... pozn. pro sebe dodělat funktory potom. Teď mám přibližné vysvětlení v Přetěžování operátorů.
|
||||||
|
Prostě to je objekt, co se chová jako funkce, ale je uložený jako objekt (jako proměnná) v kódu a může mít vnitřní funkce a proměnné. Užitečné to je třeba když chci funkci, co si umí pamatovat data z každého zavolání (třeba sčítá všechny čísla, co do ní jsou poslány jako argumenty).
|
||||||
|
# Lambda funkce
|
||||||
|
- lambda funkce jsou primárně způsob, jak zjednodušit zápis funktoru.
|
||||||
|
- [lambda gfg](https://www.geeksforgeeks.org/cpp/lambda-expression-in-c/)
|
||||||
|
- [lambda capture gfg](https://www.geeksforgeeks.org/cpp/lambda-capture-clause-in-cpp/)
|
||||||
|
|
||||||
|
Lambdy jsou divný... ale užitečný. Jde o to, že někdy chci mít možnost napsat hodně rychlou funkci, bez toho, abych ji někde musel definovat. Vytvořím tedy vlastně funkci do proměnné, a využiji ji přímo na místě a pak ji třeba hned zahodím.
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
```cpp
|
||||||
|
[](int a, int b) {return a + b;}
|
||||||
|
```
|
||||||
|
což je `[capture](parametry) -> návratový_typ { tělo }` ale hodně je optional... (třeba capture)
|
||||||
|

|
||||||
|
|
||||||
|
Příklad: Řekněme, že si někde potřebuju nutně definovat sčítání (protože mám hloupý cpp a zapomnělo to, nebo idk :( )
|
||||||
|
```cpp
|
||||||
|
auto add = [](int a, int b) {return a + b;};
|
||||||
|
|
||||||
|
int x = add(3,4);
|
||||||
|
```
|
||||||
|
|
||||||
|
Mám zde funkci, co je vlastně "uložená v proměnné". Ve skutečnosti je to ale jenom **funktor** tedy alternativa pro:
|
||||||
|
```cpp
|
||||||
|
class __Lambda123
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int operator()(int x, int y)
|
||||||
|
const {
|
||||||
|
return x + y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
__Lambda123 add;
|
||||||
|
```
|
||||||
|
|
||||||
|
**Lambda funkce se musí ukládat do proměnných typu `auto`!!
|
||||||
|
|
||||||
|
Co je *capture*?
|
||||||
|
Lambda funkce umožňuje přijmout hodnoty/proměnné z lokálního bloku a dále s nimi pracovat jako s vlastními proměnnými.
|
||||||
|
Mám 2 typy *capture* a to *capture by reference* a *capture by value*. Jedno mi umožňuje vzít referenci k proměnným/objektům a v lambdě je měnit. Druhé mi umožňuje hodnoty do lambdy prostě zkopírovat.
|
||||||
|
|
||||||
|
Př: (ukradeno z geeks for geeks)
|
||||||
|
```cpp
|
||||||
|
int main() {
|
||||||
|
vector<int> vec1 = {10, 20, 30, 40, 50}; //vektory jsou jako pole
|
||||||
|
vector<int> vec2 = {1, 2, 3, 4, 5};
|
||||||
|
|
||||||
|
auto lambda = [&vec1, vec2]() //& je ref. a druhé je pouze hodnota
|
||||||
|
{
|
||||||
|
for (int& num : vec1) {num *= 10;}
|
||||||
|
for (int num : vec2) {cout << num * 10 << " ";}
|
||||||
|
cout << endl;
|
||||||
|
};
|
||||||
|
|
||||||
|
lambda();
|
||||||
|
|
||||||
|
cout << "Vector 1: ";
|
||||||
|
for (int num : vec1) cout << num << " ";
|
||||||
|
|
||||||
|
cout << "\nVector 2: ";
|
||||||
|
for (int num : vec2) cout << num << " ";
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Další možnosti:
|
||||||
|
```cpp
|
||||||
|
auto lambda1 = [&](int x){}; //VŠECHNY externí proměnné jako refernec
|
||||||
|
auto lambda2 = [=](int x){}; //VŠECHNY externí proměnné jako hodnotu
|
||||||
|
```
|
||||||
183
Přetěžování operátorů.md
Normal file
183
Přetěžování operátorů.md
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
- *operator overloading*
|
||||||
|
- prakticky definování operací s operátory (např. +, -, /, etc.) pro objekty
|
||||||
|
- [oficiální dokumentace](https://isocpp.org/wiki/faq/operator-overloading/1000)
|
||||||
|
- [geeks for geeks](https://www.geeksforgeeks.org/cpp/operator-overloading-cpp/)
|
||||||
|
- [krátké YT video](https://www.youtube.com/watch?v=9tHu4mWtrnM&pp=ygUYY3BwIG9wZXJhdG9yIG92ZXJsb2FkaW5n) které jsem trochu vykradl
|
||||||
|
|
||||||
|
Když si vytvoříme třídu, chceme někdy mít jednoduchou práci při pracování s více jejími objekty. Pokud mám třeba třídu `ComplexNumber`" a chci sečíst 2 její objekty, musel bych normálně vytvořit vlastní funkci, která mi to umožní. Přetěžování operátorů mi ale zjednoduší práci. **Místo sepsání funkce pro součet si nadefinuji, že pokud sečtu 2 objekty pomocí operátoru `+`, tak se sečtou.**
|
||||||
|
|
||||||
|
Příklad:
|
||||||
|
```cpp
|
||||||
|
class Number
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int n;
|
||||||
|
|
||||||
|
Number(int set_n) {n = set_n;}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Number a(5);
|
||||||
|
Number b(10);
|
||||||
|
|
||||||
|
Number c = a + b; //TOTO BY SE NÁM HODILO, ALE VYHODÍ TO ERROR
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
V kódu se snažím sečíst dva různé objekty, ale nejde to, protože součet dvou objektů typu `Number` není definován (stejně jako není definován součet 2 objektů typu chyba, nebo čehokoli jiného).
|
||||||
|
**Dostanu error ve stylu:** `Invalid operands to binary expression ('Number' a...)`
|
||||||
|
|
||||||
|
**Já to ale můžu spravit tím, že si operaci pro součet sám definuju...**
|
||||||
|
```cpp
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
class Number
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int n;
|
||||||
|
|
||||||
|
Number(int set_n) {n = set_n;}
|
||||||
|
|
||||||
|
Number operator+(const Number &numA) //reference na objekt napravo od +
|
||||||
|
{
|
||||||
|
return Number(this->n + numA.n)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
Number a(5);
|
||||||
|
Number b(10);
|
||||||
|
|
||||||
|
Number c = a + b; //TED FUNGUJE
|
||||||
|
|
||||||
|
std::cout << c.n << std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Takže co se děje...
|
||||||
|
Tady je příklad binárního operátoru `+`. V podstatě to je ekvivalent zavolání funkce z objektu `a`, která by se mohla jmenovat `vrat_muj_soucet_s_necim_jak_objekt` (hrozné jméně, já vím). **V podstatě `+` je nyní funkce objektu nalevo a to co je napravo od `+` je argument této funkce.**
|
||||||
|
|
||||||
|
Je dobrý ale vědět, že operátory se nemusí přetěžovat jenom přes funkci objektu/třídy. Přetěžovat se dá i pomocí **nečlenské funkce** (normální funkce, která není součástí žádné třídy).
|
||||||
|
|
||||||
|
Příklad:
|
||||||
|
```cpp
|
||||||
|
Number operator+(const Vec& a, const Vec& b)
|
||||||
|
{
|
||||||
|
return Vec{a.x + b.x};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Toto funguje, i když to není v třídě `Number`. Pomocí nečlenské funkce lze mít součty 2 různých objektů, kde nalevo není objekt třídy, např: `5 + a`.
|
||||||
|
|
||||||
|
# Typy operátorů a jejich přetěžování
|
||||||
|
Existuje více typů operátorů valná většina z nich se dá přetěžovat. Přetěžovat ale nelze operátory:
|
||||||
|
- `.`
|
||||||
|
- `::`
|
||||||
|
- `?:`
|
||||||
|
- `sizeof`
|
||||||
|
- `typeid`
|
||||||
|
## Binární operátory
|
||||||
|
- operáty s více stranami
|
||||||
|
- `např +, -, /, %` etc.
|
||||||
|
|
||||||
|
Ve třídě:
|
||||||
|
```cpp
|
||||||
|
class Vec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int x;
|
||||||
|
|
||||||
|
Vec operator+(const Vec& other)
|
||||||
|
const {
|
||||||
|
return Vec{x + other.x};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
`a + b` je prakticky `a.operator+(b)`
|
||||||
|
|
||||||
|
Mimo funkci:
|
||||||
|
``` cpp
|
||||||
|
Vec operator+(const Vec& a, const Vec& b)
|
||||||
|
{
|
||||||
|
return Vec{a.x + b.x};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`a + b` je prakticky `operator+(a, b)`
|
||||||
|
|
||||||
|
## Unární operátory (prefixové)
|
||||||
|
- mají pouze jeden člen
|
||||||
|
- operátory prefixové se píšou před členem
|
||||||
|
- př: `-a, ++a`
|
||||||
|
|
||||||
|
Ve třídě:
|
||||||
|
```cpp
|
||||||
|
class Vec
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int x;
|
||||||
|
|
||||||
|
Vec operator-()
|
||||||
|
const {
|
||||||
|
return Vec{-x};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
`-a` je prakticky funkce `a.operator-()`
|
||||||
|
`const` v tomto případě znamená, že se nezmění objekt `this`. Ono to v tomto případě ani nedává smysl, jelikož chceme vrátit `-a`, ale nechceme změnit `a` na `-a`... Tho, ten syntax je matoucí.
|
||||||
|
**Přesněji** `const` před `{}` znamená, že metoda **nesmí měnit objekt** na kterém byla zavolaná.
|
||||||
|
Nesmím pak měnit proměnné objektu a volat jeho funkce, co nejsou stejně `const`. **Umožní mi to ale volat funkci i na const objektu**.
|
||||||
|
|
||||||
|
## Unární operátory (postfixové)
|
||||||
|
- pouze jeden člen
|
||||||
|
- píší se za členem
|
||||||
|
- mají dummy parametr -> to je trik jak odlišit `++a` od `a++`
|
||||||
|
- např: `a++`
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
Vec operator++(int)
|
||||||
|
{
|
||||||
|
Vec old = *this;
|
||||||
|
x++; //kde x je promenna Vec
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`a++` je prakticky `a.operator++(0)`
|
||||||
|
`this` je ukazatel a já nechci kopírovat ukazatel, ale to na co ukazuje, proto:
|
||||||
|
`Vec old = *this;`
|
||||||
|
|
||||||
|
**Proč se to sakra píše jako:** `operator++(int)` **s int?** (`a.operator++(0)` -> dělá kompilátor). Protože by jinak nešlo rozlišit `++a` a `a++`. Proto je konvence, že `a++` je `operator++(int)` a `++a` je `operator++()`.
|
||||||
|
|
||||||
|
## Ostatní
|
||||||
|
Operátor přístupu:
|
||||||
|
```cpp
|
||||||
|
int& operator[](size_t i)
|
||||||
|
{
|
||||||
|
return data[i];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
`a[i]` -> `a.operator[](i)`
|
||||||
|
`int&` protože jsem šetrný a vracím referenci na prvek -> něco co ukazuje na jeho hodnotu a ne jeho
|
||||||
|
|
||||||
|
**Funktor**:
|
||||||
|
```cpp
|
||||||
|
class Functor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int operator()(int x) {
|
||||||
|
return x * 2;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
`a(i)` -> `f.operator()(i)`
|
||||||
|
|
||||||
|
Funktory jsou důležité! Funktory jsou objekty, které se chovají jako funkce a hádám (teď to nedokážu říct), že o nich uslyšíme ještě dost.
|
||||||
|
Jejich hlavní smysl je **být něco mezi objektem a funkcí**. Funkce nemá žádnou paměť, což znamená, že vždy dává stejný výsledek při stejném vstupu (i mean ne nutně, jako když použiju náhodná čísla, tak ne... buuuhuuu, ale chápeme se...).
|
||||||
|
Funktor mi umožňuje udělat objekt, který "předstírá, že je funkce". Pamatuje si svoje operace a může ukládat do vnitřních proměnných při každém zavolání/upravě, etc...
|
||||||
|
|
||||||
|
Dále jde přetěžovat třeby `->`. Operátorů je opravdu hodně...
|
||||||
51
Reference.md
Normal file
51
Reference.md
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
Reference je v podstatě jako **konstantní ukazatel** s jistými omezeními:
|
||||||
|
|
||||||
|
- musí být inicializována při vytvoření
|
||||||
|
- nemůže být null
|
||||||
|
- nedá se měnit, kam ukazuje (stejně jako konst. uk.) a neumí aritmetiku
|
||||||
|
|
||||||
|
**Používá se jako normální proměnná se jménem (bez \*)**
|
||||||
|
|
||||||
|
Zásadní mentální rozdíl taky můžeme hledat v tom, co to vlastně je. Ukazatel je proměnná s adresou v paměti, zatímco reference je alias pro objekt/proměnnou.
|
||||||
|
|
||||||
|
```
|
||||||
|
int x = 5; # nějaká proměnná x
|
||||||
|
|
||||||
|
int& r = x; #inicializace reference, musí mít hodnotu.
|
||||||
|
#int& r; #není možné
|
||||||
|
|
||||||
|
int* p; # ukazatel to umí - pro srovnání
|
||||||
|
p = &x;
|
||||||
|
```
|
||||||
|
|
||||||
|
Referenci nelze přesměrovat na jinou adresu/proměnnou
|
||||||
|
```
|
||||||
|
int a = 1;
|
||||||
|
int b = 2;
|
||||||
|
|
||||||
|
int* p = &a; #ukazatel ukazuje na a
|
||||||
|
p = &b; # ukazatel ukazuje na b
|
||||||
|
|
||||||
|
int& r = a; #reference ukazuje na a
|
||||||
|
r = b; #reference nabírá hodnoty b, teď a = b
|
||||||
|
# a = b; je ekvivalentní
|
||||||
|
```
|
||||||
|
|
||||||
|
- Reference nemá vlastní adresu, není to proměnná a nebo objekt. Pokud se pokusím získat adresu reference, dostanu adresu objektu, na který ukazuje.
|
||||||
|
|
||||||
|
K čemu to je dobré?
|
||||||
|
- stále můžu používat referenci na předání funkci. **To je hlavní důvod existence referencí - bezpečnější a čitelnější předávání parametrů místo ukazatelů.**
|
||||||
|
```
|
||||||
|
void increment(int& r)
|
||||||
|
{
|
||||||
|
r++; #melo by zvysit jakoukoli promennou, co je predana jako parametr
|
||||||
|
}
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
int x = 42;
|
||||||
|
increment(x); #zde predam proste puvodni promennou
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- **Je to omezenější než ukazatel a proto je tu menší šance, že se uživatel střelí do nohy. Když to stačí, mělo by se to používat místo ukazatele. Doporučuje se to.**
|
||||||
98
Výjimky.md
Normal file
98
Výjimky.md
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
Výjimka je způsob jak aktivně kontrolovat správný chod programu a popasovat se s nečekanými chybami. V podstatě mě zajímají 3 hlavní operátory a to:
|
||||||
|
- **try** -> blok, ve kterém se snažím zachytit chybu
|
||||||
|
- **catch** -> blok, který řeší co se stane, když nastane chyba
|
||||||
|
- **throw** -> operátor, který umí chybu vyhodit
|
||||||
|
|
||||||
|
Dále se u základní C++ setkáme s třemi knihovnami, které s chybami souvisí a to?
|
||||||
|
- `<exception>` - základní funkcionalita chyb
|
||||||
|
- `<stdexcept>` - seznam typů chyb, které můžeme využít na "házení" při problémech
|
||||||
|
- `<new>` - umí vyhazovat chyby typické u práci s pamětí (třeba nedostatek místa)
|
||||||
|
|
||||||
|
Funkcionalitu musíme přidat pomocí `#include <exceptions>`
|
||||||
|
|
||||||
|
Hlavní smysl chyb je zachytit nečekané věci v programu. Neměli bychom řešit problémy s kterými počítáme. Zatímco můžeme řešit třeba dělení nulou, které nestane při očekáváném vstupu od uživale (a nějaký typ chyby na to existuje), tak protože to čekáme a připravujeme se na to, tak bychom to měli řešit spíše jinak. Chyba má smysl hlavně v případech, které nelze odtušit a to například:
|
||||||
|
- otevření souboru, který je prázdný
|
||||||
|
- nedostatek paměti
|
||||||
|
- přetečení
|
||||||
|
Chyby jsou praktické, ale zatěžují program. Proto je třeba s nimi být opatrný a nepoužívat je na všechno zbytečně (a také samozřejmě kvůli přehlednosti).
|
||||||
|
|
||||||
|
Pro embedded systémy existuje alternativní způsob jak řešit chyby, který není tak náročný a to `std::optional` a `std::expected` v C++23.
|
||||||
|
|
||||||
|
# Základ
|
||||||
|
|
||||||
|
Strukturálně program s chytáním chyb vypadá:
|
||||||
|
```cpp
|
||||||
|
try
|
||||||
|
{
|
||||||
|
# zde je blok kde hledám chybu
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
# zde je blok kde řeším chybu
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Try
|
||||||
|
`try` funguje jednoduše, všechno co je uvnitř je zpracovaný výjimka a můžu řešit, co s ní pak udělám pomocí `catch`. S tím pak můžu řešit důmyslnou logiku výjimek, kdy na různých vrstvách programu řeším různé problémy dle toho, kdy se mi to hodí.
|
||||||
|
Například na nízké vrstvě můžu vyhodit nějakou chybu ze špatné operace. na střední vrstvě se rozhodnu, jestli je řešitelná (můžu ji třeba napravit) a nebo jestli ne. Pokud ne, tak ji pošlu do vysoké vrstvy, která ji chytí a vypíše uživateli a ukončí proces, kde vznikla.
|
||||||
|
|
||||||
|
Všechny chyby, které nejsou chyceny pomocí `try` spustí `std::terminate`, což způsobí pád programu.
|
||||||
|
|
||||||
|
Tohle je vhodné si spojit ještě s konceptem **stack unwinding**. To je jak chyba cestuje -> stále nahoru v cestě programu (stack -> cesta volání - spíš paměť, kde je cesta uložena). Všechno putuje nahoru a když to skončí úplně nahoře v main, tak je průser.
|
||||||
|
|
||||||
|
## Throw
|
||||||
|
`throw` vyhazuje chybu. Může to být text, např: `throw "Tady je chyba\n";` , ale obecně je spíš vhodné vyhodit nějaké oficiální objekt představující nějaký typ chyby z `<stdexcept>`.
|
||||||
|
|
||||||
|
např: ` throw std::invalid_argument( "received negative value" );`
|
||||||
|
- zde je možné poslat společně s typem chyby argument se zprávou...
|
||||||
|
|
||||||
|
|
||||||
|
## Catch
|
||||||
|
V bloku `catch`, který následuje za `try` se řeší, jak se zachovat v případě nějaké chyby
|
||||||
|
```cpp
|
||||||
|
try
|
||||||
|
{
|
||||||
|
#něco
|
||||||
|
}
|
||||||
|
|
||||||
|
#catch("Text") {} #nedává smysl, nechytá se hodnota, ale typ
|
||||||
|
catch(const std::bad_alloc& e) {} #vyjímka špatné alokace
|
||||||
|
catch(int) {} #chytí všechny integery
|
||||||
|
catch(std::exception) {} #chytí všechny chyby
|
||||||
|
catch(...) {}#chytí úplně všechno
|
||||||
|
```
|
||||||
|
|
||||||
|
`Catch` funguje jako funkce. Má argumenty, které nejsou hodnoty, ale typy hodnot, které jdou "zavolat". Proto nemůžu chytat text, ale můžu chytat např. `const char* e` -> a `e` je to co se předá.
|
||||||
|
|
||||||
|
v případe `catch(const std::bad_alloc& e) {}` se používá [[Reference]] protože objekt může být teoreticky velký a my ho nechceme kopírovat.
|
||||||
|
## What()
|
||||||
|
`.what()` je funkce chybových objektů. Ta vypisuje jejich textovou hodnotu.
|
||||||
|
Například pro `throw std::invalid_argument( "received negative value" );`
|
||||||
|
vypíše `"received negative value"`.
|
||||||
|
|
||||||
|
Volal bych třeba
|
||||||
|
```cpp
|
||||||
|
catch(const std::bad_alloc& e)
|
||||||
|
{
|
||||||
|
std::cout << e.what()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## set_terminate a terminate()
|
||||||
|
Když nastane situace, kdy se dojde k nějakému fatálnímu programu, na který program není připraven, zavolá se `std::terminate()`. Ten zavolá `abort()` a ukončí program.
|
||||||
|
To může nastat, když výjimka není zachycena, ale případů je víc:
|
||||||
|
- během stack unwindingu (tedy při opouštění funkcí po `throw`) dojde k další výjimce
|
||||||
|
- vyhodí se výjimku z destruktoru během unwindingu
|
||||||
|
- porušení pravidla `noexcept` (funkce označená jako `noexcept` vyhodí výjimku)
|
||||||
|
|
||||||
|
`terminate` je poslední funkce, která se zavolá před ukončením programu a nevrací dále dál tok programu.
|
||||||
|
My pokud chceme můžeme nastavit vlastní funkci `terminate`, pro větší kontrolu nad programem pomocí `std::set_terminate(my_func);`
|
||||||
|
|
||||||
|
**Pozn**: destruktory nesmí házet výjimky proto, protože při výjimce nastane situace, kdy se ukončuje funkce a destruktory se volají. Pokud by destruktor vyhodil výjimku, mohla by nastat situace, kdy jsou 2 výjimky najednou, což je problém.
|
||||||
|
# Typy chyb
|
||||||
|
|
||||||
|
- runtime chyby -> range, overflow, etc.
|
||||||
|
- logické chyby -> domain, out_of_range...
|
||||||
|
- bad_cast
|
||||||
|
- bad_function_call
|
||||||
|
- bad_alloc -> většinou nedostatek paměti od new...
|
||||||
Reference in New Issue
Block a user