# 11 лекция - C++
(07.05.2022)
## Исключения
В си для обработок ошибок приняты коды возврата.
```c
float strtonnm(conat char *); //функция для преобразования строку в число
//как вернуть ошибку?
struct result strtonnm(conat char *); //вернуть структуру (реже всего)
float strtonnm(conat char * x, int *error); //принять указатель на переменную означающую ошибку (встречается чаще)
{
if (x == NULL)
{
*error = 1; //в качестве error нельзя давать null
return 0; //возвращает некий ноль
}
//...
}
int strtonnm(conat char * x, int *error); //поменять местами значение и переменную ошибки
{
if(!x) //x==NULL - тоже самое
{
if(error) //делаем параметр error опциональным
*error = 1;
return 0;
}
}
int err;
float f = strtonnm(argv[1], &err);
if (err != 0)
{
//...
}
```
Какие коды использовать? Есть 3.5 подхода:
* Использовать bool, `true` - всё хорошо, `false` - всё плохо
* Использовать int, `0` - всё плохо, `НЕ 0` - всё хорошо
* Использовать signed int, `>=0` - всё хорошо, `<0` - всё плохо
* ??
В C++ сделали исключения
```c++
float strtonnm(const char *x)
{
if (!x)
throw "NULL pointer"; //бросить ошибку в окружающее пространство
//...
}
int main(int argc, char **argv)
{
try
{
float f = strtonnm(argv[1]); //если обратились в следующий аргумент после последнего выхода за границы не будет - спец случай
}
catch (int x) //здесь ловит int
//можно писать даже без названия переменной, если не интересно значение переменной
{
//...
}
catch (const char *y) //здесь ловит const char * (костантные строки)
{
throw y; //бросить дальше
//...
}
catch (...) //ловить всё, что не поймали выше
//нельзя узнать значение, очевидно
{
throw; //бросить дальше, даже если непонятно что приняли
//throw Без аргументов только для блоков catch
}
//...
}
```
> `catch` проверяется последовательно
> Если написать `catch` по базовому классу, то он ещё поймает ошибку
с классом наследником
> Все стандартные плюсовые библиотеки бросают ошибки
Есть проблема с тем, что ошибка будет пробрассываться вверх до блока `catсh`, и динамические обьекты не будут освобожденны
> При бросание ошибки вызываются деструкторы локальных обьектов (не динамических)
> Привязывать освобождение обьектов надо к деструктору, `RAII` - концепция
### Минусы
1) Не бесплатно, даже если нет иключения
2) ???
3) Функция может бросить что угодно (в новом стандарте `noexcept`, обещание не бросать, если броситься - программа сразу `undefine behavier`) (позволяет компилятору оптимизировать код)
4) Довольно сильно ограничивает оптимизатор
```c++
int main() noexcept
{
//...
}
```
> Компятор может скомпилировать только исключения брошенные кодом скомпилированным от него же...
> `try` не ловит исключения деления на `0`, обращение сквользь `NULL`, только то, что бросили через `throw`
```c++
float strtonnm(const char *x) try
{
//...
}
catch()
{
//...
}
```
> Так можно поймать исключения конструктора внутри класса
> в конструктор не сможет так поймат исключение
```c++
class A
{
int f() const;
mutable int x; //могут менять методы const
}
```
`int *arr = new(std::nothrow) int[10];` (заголовочный файл `include <new>`)