Slide 1

Slide 1 text

22 февраля 2022 [email protected] Анастасия Андреевна Корепанова Обработка ошибок

Slide 2

Slide 2 text

2/35 2/35 Что такое ошибка? Ошибка – сбой, который не даёт функции успешно завершиться (возможно, не может даже начаться): 1.Нарушены предусловия. Например: передача float вместо int 2.Нет возможности выполнить постусловие. Должна вернуть значение – не может его получить. 3.Нет возможности восстановить инвариант, за поддержку которого она отвечает.

Slide 3

Slide 3 text

3/35 3/35 Ошибка программиста и исключительная ситуация 1/3 Ошибка программиста – неправильно написан код. Ошибки в логике программы, которые происходят из-за неправильно написанного кода, т.е. это ошибки программиста. Исключительная ситуация – ошибка возникает по независящим от нас обстоятельствам от взаимодействия с внешними ресурсами.

Slide 4

Slide 4 text

4/35 4/35 Ошибка программиста и исключительная ситуация 2/3 • При сохранении файла на диск оказалось, что место на диске кончилось. • Удалённый сервер недоступен. • Видео модуль не загрузился, т.к. на компьютере не оказалось соответствующего кодека. • Разыменование нулевого указателя при попытке обратиться к видео модулю, который не загрузился. • У сайта оказался некорректный SSL сертификат. • Выход за границу массива при обработке некорректного SSL сертификата.

Slide 5

Slide 5 text

5/35 5/35 Ошибка программиста и исключительная ситуация 3/3 • При сохранении файла на диск оказалось, что место на диске кончилось. • Удалённый сервер недоступен. • Видео модуль не загрузился, т.к. на компьютере не оказалось соответствующего кодека. • Разыменование нулевого указателя при попытке обратиться к видео модулю, который не загрузился. • У сайта оказался некорректный SSL сертификат. • Выход за границу массива при обработке некорректного SSL сертификата.

Slide 6

Slide 6 text

6/35 6/35 Определение ошибок на этапе разработки • Static_assert позволяет определять ошибки на этапе компиляции. • Пример: • Assert позволяет определять ошибки на этапе выполнения. • Пример: Только на время разработки!

Slide 7

Slide 7 text

7/35 7/35 Журналирование (логирование) • boost_log • Наличие журнала работы программы помогает понять, что с ней происходит. • Что логировать? • Время, уровень, место, где происходит ошибка, сообщение • Зачем логировать? Понимать, что происходит!

Slide 8

Slide 8 text

8/35 8/35 Crash reporting При возникновении ошибки возможно получить не только описание ошибки, но и полное состояние программы во время падения. Пример инструментов: Google break-pad или Microsoft minidumps Что полезно: раскрутить стеки, понять, что где вызывалось Бибилотеки, которые использует приложение, их местоположение Если сборка релизная, то многое может быть непонятно в результате работы компилятора Если есть дамп памяти, можно под дебагером его загрузить (они тяжёлые)

Slide 9

Slide 9 text

9/35 9/35 Исключительные ситуации в программе Найти ошибку Передать к месту обработки Решить, что с ней делать Может происходить в разных местах программы

Slide 10

Slide 10 text

10/35 10/35 Обработка ошибок Данные об ошибке необходимо доставить от места возникновения до места обработки

Slide 11

Slide 11 text

11/35 11/35 Как обработать ошибку? 1/4 Возврат статуса операции Вставить глобальную переменную и вернуть какое-нибудь невалидное значение (например, false) Вернуть код ошибки Остановить программу Сгенерировать исключение

Slide 12

Slide 12 text

12/35 12/35 Как обработать ошибку? 2/4 • Возврат статуса операции: • Нет информации об ошибке • Изменили сигнатуру функции

Slide 13

Slide 13 text

13/35 13/35 Как обработать ошибку? 3/4 • Вставить глобальную переменную и вернуть какое-нибудь невалидное значение (false, -1 и т.д.) - Вернуть невалидное значение не всегда возможно - Возникают сложности в многопоточном приложении. Если она правда глобальная на программу, то потоки будут конфликтовать за пользование этой переменной. Как решается эта проблема?

Slide 14

Slide 14 text

14/35 14/35 Как обработать ошибку? 4/4 • Вернуть код ошибки. Иногда функция возвращает код завершения, он же код ошибки, если имеет ненулевое значение; в других случаях часть диапазона значений функций выделена под коды ошибки. + Работает, С библиотеки так и работают. – часто забывают проверить – приводит к разбуханию кода

Slide 15

Slide 15 text

15/35 15/35 Исключения 1/3 • Исключение – это объект с информацией об ошибке. Реализован механизм его удобной передачи от места возникновения до места обработки. • В месте возникновения ошибки исключение «бросается», в месте обработки «ловится».

Slide 16

Slide 16 text

16/35 16/35 Исключения 2/3 • невозможно игнорировать • распространяется автоматически • выносит обработку из основного потока выполнения • незаменимо в конструкторах и операторах. У них нет возвращаемого типа, так что нельзя вернуть код ошибки. Проблемы?

Slide 17

Slide 17 text

17/35 17/35 Исключения 3/3 Проблемы • Разбухание кода • Издержки компилятора • В плюсах старых версий не применяется, осуждается наравне с GOTO (почему?) • Обязательно использование RAII

Slide 18

Slide 18 text

18/35 18/35 Stack unwinding 1/5 • При возникновении исключения объекты на стеке уничтожаются в естественном (обратном) порядке.

Slide 19

Slide 19 text

19/35 19/35 Stack unwinding 2/5 • При возникновении исключения объекты на стеке уничтожаются в естественном (обратном) порядке.

Slide 20

Slide 20 text

20/35 20/35 Stack unwinding 3/5 • При возникновении исключения объекты на стеке уничтожаются в естественном (обратном) порядке.

Slide 21

Slide 21 text

21/35 21/35 Stack unwinding 4/5 • При возникновении исключения объекты на стеке уничтожаются в естественном (обратном) порядке.

Slide 22

Slide 22 text

22/35 22/35 Stack unwinding 4/5 • При возникновении исключения объекты на стеке уничтожаются в естественном (обратном) порядке. • Чтобы это реализовать, немного теряется эффективность программы • Какие ещё проблемы?

Slide 23

Slide 23 text

23/35 23/35 Что можно бросать в качестве исключения? Можно что угодно! Но не всё нужно…

Slide 24

Slide 24 text

24/35 24/35 Стандартные классы исключений Стандартные классы ошибок: • logic_error: domain_error, invalid_argument, length_error, out_of_range • runtime_error: range_error, overflow_error, underflow_error

Slide 25

Slide 25 text

25/35 25/35 Исключения в стандартной библиотеке • Метод at контейнеров array, vector, deque, basic_string, bitset, map, unordered_map бросает out_of_range. • Оператор new T бросает bad_alloc. • Оператор typeid от разыменованного нулевого указателя бросает bad_typeid. • Потоки ввода-вывода.

Slide 26

Slide 26 text

26/35 26/35 Когда использовать исключения? 1/2 Правила хорошего тона: • Разделять ошибки программиста и исключительные ситуации • Использовать assert • Использовать только стандартные классы исключений или производные от них • Бросать по значению, отлавливать по ссылке. Почему? • Отлавливайте все исключения в точке входа

Slide 27

Slide 27 text

27/35 27/35 Когда использовать исключения? 2/2 Когда применяются исключения: • Обрабатываемая ошибка просходит нечасто. • Ошибка серьёзная,и без её обработки невозможно дальнейшее исполнение программы. • Ошибка не может быть обработана там, где она возникла. • Нет более подходящего способа вернуть код ошибки.

Slide 28

Slide 28 text

28/35 28/35 Конструкторы Исключение – это единственный способ прервать конструирование объекта и сообщить об ошибке. • Исключения, которые вылетают из конструктора, корректно обрабатываются. При исключении в конструкторе не будет вызван деструктор, потому что деструктор вызывается, если объект уже создан.

Slide 29

Slide 29 text

29/35 29/35 Деструкторы • Исключения не должны покидать деструкторы

Slide 30

Slide 30 text

30/35 30/35 Что не так в этом коде? 1/2

Slide 31

Slide 31 text

31/35 31/35 Что не так в этом коде? 2/2

Slide 32

Slide 32 text

32/35 32/35 Деструктор и без блока try-catch? 1. throw std::runtime_error("Some message"); 2. int * data = new int[size]; 3. delete [] data; 4. // data_ - это поле класса типа std::vector for (auto s : data_) { len += s.size(); } 5. // data_ - это поле класса типа std::vector size_t len = 0; for (auto & s : data_) { len += s.size(); }

Slide 33

Slide 33 text

33/35 33/35 Деструктор и без блока try-catch? 1. throw std::runtime_error("Some message"); 2. int * data = new int[size]; 3. delete [] data; 4. // data_ - это поле класса типа std::vector for (auto s : data_) { len += s.size(); } 5. // data_ - это поле класса типа std::vector size_t len = 0; for (auto & s : data_) { len += s.size(); }

Slide 34

Slide 34 text

34/35 34/35 Материалы Основные источники: • Курс "Программирование на языке C++ (продолжение)". Лектор А.В. Смаль. https://stepik.org/course/3206/info • Курс "Программирование на C++, часть 2 (весна 2019)". Лектор В.М. Лесин. https://www.youtube.com/playlist?list=PLlb7e2G7aSpRs7YafQ1GgJvyRku 10m1RN Дополнительные материалы: • Реализация раскрутки стека разными компиляторами C++ https://habr.com/ru/post/208006/

Slide 35

Slide 35 text

22 февраля 2022 [email protected] Анастасия Андреевна Корепанова Обработка ошибок