Базовый курс C++ (MIPT, ILab). Lecture 11. Исключения

preview_player
Показать описание
Лекции в бакалавриате МФТИ по C++ на русском языке.

В этой лекции мы рассмотрим механизмы обработки ошибок в языке C++, поговорим о том как правильно кидать и ловить исключения. Потом мы затронем такую важную тему как безопасность исключений и избавимся от ложного чувства защищённости.

Лектор: Константин Владимиров
Дата лекции: 22 ноября 2021 года
Съёмка: Владислав Белов.
Звук: Дмитрий Рябцев.

Доклад Калба.

Timeline:
00:00 Обработка ошибок в стиле C и её проблемы в C++
13:30 Нелокальные методы обработки и виды исключений
25:30 Знакомство с исключениями
30:50 Как правильно бросать и ловить исключения
44:50 Стандартная иерархия исключений
59:40 Нейтральность
1:08:25 Ложное чувство безопасности
1:15:30 Гарантии безопасности
1:22:45 Линия Калба
1:30:00 Обзор литературы

Errata:
* 1:20:04 в цикле перед приращением запятая вместо ;
Рекомендации по теме
Комментарии
Автор

На 42 - 43 минуте сначала вызывается деструктор локальной копии Base, а потом уже деструктор оригинального Derived и его базы.
А на лекции это звучит будто при наследовании первым вызывается деструктор базового класса.

bochkarevartem
Автор

Летят два исключения. Одно говорит:
— Жаль, погода нелетная.
Другое:
— Ничего. Лишь бы программист хороший попался.

Спасибо за лекцию!

pavelrid
Автор

Линию Калба можно например границей (линией) исключений (exceptions border (line)) назвать, запомнить легче и сразу понятно что это.

Konstantin_Evdokimov
Автор

1:20:04 в цикле перед приращенем запятая вместо ;

frest
Автор

Так что получается, нужно все заворачивать в try-catch?

stanislavstanislavius
Автор

42:40 Вы говорите: "т. е. на экране будет cначала деструктор ~Base, потом деструктор ~Derived, а потом деструктор Base для этого объекта, потому что это новый объект". Но деструкторы вызываются в порядке от дочерних к базовому. На самом деле объекты будут уничтожаться после обработки исключения в обратном порядке: сначала новый - Base, за ним старый - Derived.

Base1() Derived1() Base2(const&)
catch
~Base2() ~Derived1() ~Base1()

bitrebus
Автор

-На --1:26:00-- в цикле while (tmp.size() < used_) tmp.push(arr_[tmp.size()]), разве не должно быть tmp.push(arr_[tmp.used()], если size является аналогом capacity из стандартного вектора?-

*UPD.* Увидел в следующей лекции, что size() возвращает used_.

maximpahomov
Автор

На 49 слайде разбирается, что 6-ой из 10 операторов присваивания Т может бросить исключение.
А в строчке arr_= new T[rhs.size_] 6-ой из 10 конструкторов по умолчанию T также может бросить исключение.
Про это ни слова не сказано.
Я бы студентам рассказал про гарантии new и, в частности, для new[] (commit/rollback?).
Со всем уважением! Но я, рожденный в стране советов, не могу удержаться от советов))

alexbur
Автор

28:34 при переходе с 20 на 21 слайд, возможно я ошибаюсь, но фрейм с деструктором 0x...c70 уже же сняли, не должен ли обновиться адрес в this у деструктора на строчке #0 бэктрейса? Это ведь уже деструктор другого объекта.

На мой взгляд пример на слайде 23 не такой уж и абсурдный, есть у нас какая-то математическая библиотека, на базе нее построили консольное приложение, там вывели в catch блоке сообщение на консоль. Завтра реализовали калькулятор с кнопочками и выводить ошибку будем в модальное окно. Важно, что в самой функции divide мы не знаем из какого типа приложения нас вызывают и поэтому нельзя взять и просто вывести на консоль, ее может и не быть.

samolisov
Автор

47:01 Ого! Интересно. Вопрос про разыменование null указателя заиграл новыми красками. Можно на собеседованиях покрасоваться.

ddvamp
Автор

Если я правильно понял технику линии Калба: мы создаем временный объект, с которым делаем все необходимые нам операции - выделение памяти и т.д., в течение которых может вылететь исключение - это все выше этой линии( не меняем состояние, а можем бросить исключение), а затем, лишь меняем этот временный объект с текущим. Вопрос, так действительно желательно(настоятельно рекомендуется) писать большинство классов(по типу как std::vector)?

qhogqbq
Автор

1:11:43 Можно уточнить, почему всё-таки будет исключение в copy ctor в цикле? Или это просто предположение а вдруг?

qhogqbq
Автор

17:00 разве при undefined instruction exception операционка не посылает какой-нибудь сигнал (который можно перехватить)?

FeelUs
Автор

Что по стандарту должно произойти при двойном освобождении памяти?

RichardGraveman
Автор

Здравствуйте, могу ошибаться, пожалуйста проверьте 5-й слайд:
atoi, atol, atoll - возвращает 0 в случае невозможности преобразования и в случае переполнения "behavior is undefined" ист. cppreference
по atoi источник freebsd org : "ERRORS The function atoi() need not affect the value of errno on an error." В том же источнике характерные errno выставляет strtonum.
"The HUGE_VALF, HUGE_VAL and HUGE_VALL macros expand to positive floating point constant expressions which compare equal to the values returned by floating-point functions and operators in case of overflow " , вероятно тогда общее описание на слайде подходит для преобразования в число с плавающей точкой strtod, strtof, strtold
Спасибо за лекции!

meshcheriakov
Автор

42:40. Здравствуйте, вы говорили, что происходит срез к базе, но происходит не совсем то, что ожидается. Если мы добавим в наши классы ещё вывод конструкторов, то как только создаётся Derived, вызывается База, потом Наследник. После чего кидается в исключение, кажется, что должен вызваться конструктор Базы, но этого не происходит (Вы знаете почему?), как только b выходит за пределы, то вызывается деструктор Базы, а потом деструкторы Наследника и База.

Непонятно, почему не создаётся объект базы в catch(Base) через конструктор

dmitrydemis
Автор

Вроде бы оператор бул у стрима не равносилен good / bad, там всё несколько запутанней...

niklkelbon
Автор

1. Механизм исключительных ситуаций, в котором их понимает C++, тесно завязан на явном понимании/представлении, что такое стек вызовов...
Абстрактная машина языка С++ никак, насколько я знаю, не описывает стеки вызовов и данных, поэтому при работе с исключениями возникают проблемы. Исключения бы стали самим самой разумеющимися, если бы язык давал явное описание фрейма функции.
2. Механизм исключений по своему поведению очень похож на механизм goto, который не приветствуется в разработке. Оба этих механизма невероятные возможности изменения поведения программы, но требуют недюжего ума, чтобы уследить за всем...

kirillgalitskiy
Автор

Вроде назван у курса 'базовый' но я все равно местамт не понимаю о чем идет речь, требуется знание предыдущих серий видимо. . )

xaoc
Автор

На 51:41 некорректная формулировка?. По [except.throw]#6#7 внутри catch блока исключение уже не активно.

ddvamp