лекции (2015) (1160856), страница 10
Текст из файла (страница 10)
На основе Ады. В стандартной библиотеке появился std::exception. Генерируются часто самимкомпилятором (например, для dynamic_cast<...>(...) ===> bad_cast).Visual Basic.ON <имя> <реакция> (обычно GOTO метка) – оператор установки обработчика (локально впроцедуре).Error.raise( номер ИС, сообщение) – бросить ошибку. Если ON не установлен, тораспространяется вверх по программе (т.к. интерпретатор), если не нашли ==> отладчик.Всего 4 варианта обработки:1.resume – повторить оператор.2.resume <метка> – начать с метки3.resume next - начать со следующего оператора.4.exit subСаша & Стас ([947-968], завершено)Исключения.
Принцип динамической ловушки. Свертка стекаИС - исключительная ситуация.Семантика завершенияВыдавший? блок обязательно завершается (составной оператор)// т.е. любой блок может иметь исключенияAda:beginоператоры(блок реакций)when ис1|ис2|ис3|...|исN => операторы реакции 1when исN[l,1]|..|исN[l,k] => операторы 2when othersendно при этом обязательно выходим из блока, (можем вызвать заново, но это не возобновление, аперезапуск)● Распространение -- для и-проуры? + выдаем полный стек вызовов, если вышли из прист.?● Обработка: собственно выполняются операторыraise; -- частичной обработки -> перевозбуждение (вроде throw без юрзов?)при этом никакой ???, кроме имени с ИС не связывается -> недостаток (т.к. просто реагируется: ???в списке целочисленного идентификатора)C++45ИС ⇔ с типом данных связывается (int, char * и т.д.)(const char * what()) -- class std::exception в STL появилсяthrow expression; -- объект ИСВыделяется особая память для ровно 1 объекта ИС (не динамическая, но особая) + есть явноепонятие “свертка стека” (т.к.
происходит вызов деструкторов всех созданных? объектов)Принцип динамической ловушки заключается в том, что выбирается реакция на ИС, ближайшаяпо динамической цепочки вызовов.Свертка стека - процесс уничтожения переменных в аварийном блоке (там где произошла ИС). Длялокальных переменных или объектов работают деструкторы.Синтаксис:try {операторы;} // дальше идет список “ловушек”catch (Тип [имя]) {блок реакции}….catch (Тип [имя]) {блок реакции}catch (...) { … }Тип -- строгое отождествелние с типом, без преобразований, кроме производный -> базовый.имя -- если хотим обращаться к инфуги? вызя? объектаВажно! В момент свертки стека не должно быть исключений (места для него уже нет).
Программазавершится аварийно.Если нет больше try блоков выше по стеку, то для? в данной точке можно завершиться -авост? ->можно самостоятельно вызвать библиотечную функцию terminate();+ установить свой обработчик set_terminate(новый); // отдать? старый обработчикС#, JavaИС - специальный класс ошибок.+ есть член-данные?, Exception InnerException внутри класса Exception чтобы “разрасталось”исключение => можно выдать стекИС делятся на пользовательские и системные. Возбуждение пользовательских ИС происходит вкоде пользователя, а системных ИС - в коде, генерируемым компилятором.Пользовательские ИС в C++ наследуются от класса exception, в C# - от ApplicationException, в Java от Exception.Уничтожение объектов носит недетерминированный характер в языках с автоматической сборкоймусора.В C# и Java используется конструкция - try{} - ловушки - finally {код обязательно выполнится}C#Java46Класс Exception (непосредственныйпотомок Object, от него наследуюутся всеошибкиthrow new Err();catch (Exception ex) - все поймаетcatch { операторы } - аналог catch (...) {}, хотяи не нуженКласс Throwable{свертки стека вообще нет, деструктор именно при разрушении объекта(finalize),они вообще могут не выполняться,вызовятся? только при сборке мусора}catch(Exception ex)finally {...} -- вызывается всегда в конце tryблока в независимости от способа выходаиз try блока и обработки исключенийthrow new Err();В Java тоже RAII реализуется {Resource Acquisition Is Initialization}Res x = new Res();try {….}finally {освобождение X}То есть нет явного вызова финализаторов, но есть возможность задать явное уничтожение (нужно,чтобы класс реализовывал ???)IDisposable {void Dispose();}тогда:var img = Image.FromImage(“some.png”)try {// работа с img}finally {// нужно явно привести к интерфейсу, если явно реализовали интерфейс// “явная реализация интерфейса”((IDisposable)img).Dispose(); //освобождение картинки}Альтератива -- использование using(имя) // имя переменной, которая реализует IDisposableusing (Image img = Image.FromImage(“some.png”)){//work with image}//img автоматически освобожденКомпилятор сам подставит try/finally + проверит, что класс действительно реализует IDisposablePython:Error -> либо throw Error, либо throw <class, наследующий от Error>// вроде как в Python raise (точно raise).try:операторы<ловушки>except имя1:47…except:finally:else: -- когда вышли нормально + сработал finally в концеJS:try {… throw new Error(...);}catch (e) { … }e -- имя, без типов, т.к.
изначально подразумевается, что всегда выбрасывается объект Error.!Нет множественных ловушек, т.к. только 1 Объект - ErrorКомментарий: Семантика возобновления работает в основном только в маленьких проектах,поэтому в большинстве языков реализованна именно семантика завершенияСпецификация исключений: (только в С++ и Java)С++:void f() throw (cписок типов)); {function body}// спецификация опциональна// список типов может быть любымЭто означает, что это -- контракт, что кроме указанных исключений никаких других не появится.Это гарантирует, что все ИС не из списка либо не возникают, либо обрабатываются внутри функции.Пример:void f() throw (X, Y, Z);void suppress() throw(){try {f();}catch (X x) {}catch(Y y) {}catch(Z z) {}}В случае, если через функцию проходит не специфицированное исключение -> unexpected() +set_unexpected() { по сути terminate }, при этом в этой же точке более специфицированно местопадения,-> подразумевается, что любой деструктор как будто специфицирован throw() {т.к.
не долженвыбрасывать исключений}Java:class X {void f() throws список типов ИС (все наследники Throwable) { … }void g() [пустой список по умолчанию -> по умолчанию ничего не можетбросать] { … }-> throws обязателен -> уже на этапе компиляции легко проверять -> компилятор гаранитирует● однако есть JNI -- а это по сути L-? там нет исключений, а ошибки возникать могут }48●существуют ошибки, на которые нельзя реагировать (ошибки процессора, неожиданно, редко,но в любом месте), но на? них не надо реагироватьВиды ошибок в Java● class Error extends Throwable{...} - ошибки фунционирования Java-машины и JRTE● class Exception extends Throwable{...} - базовый класс для пользовательских ИС, их нужноуказывать в throws● class RuntimeException extends Exception {...} - базовый класс для ошибок выхода за границумассива, нехватки памяти и т.
п., на них не обязательно реагировать, но можно, какследствие, можно опускать в throwsADA:Создание исключения:New_Exception: exception;Поднятие/возбуждение исключения:raise New_Exception;Отлов исключения:beginRise_Exception;exceptionwhen New_Exception =>Do_Smth;end;Исключения+1. Код обработки симализован? - легче читать и писать2.
[Проброс инерции]? - за счет одного исключения, не надо делать кострукцииif (...) {return -1;}1. Асинхронность - в любом месте неожиданно может возникнуть любое количество ошибок2. Писать хорошие отказоустойчивые программы тоже? сложноНаследование●●расположение в памяти (layout)множественная теория типовC++: производный T1 < T2 базовый, где < -- отношение наследования между типамиSmalltalk:переменная -> класса (static в C++)-> экземпляра -- все инкапсулированные -> надо ввести get и setпри этом все операции -- обмен сообщениями:{ 5 + 3 - числу “5” посылается сообщение “+” с аргументом “3” ⇔ 5.+(3) }-> при наследовании наследуются все свойства и атрибуты(+ операции)можно добавить новые; при этом в стандарте нигде не сказано, что нельзя реализовыватьнепрерывной памятью[-----память под базовый-----][---память под производный---]49this в C++: X * const this (const -- нельзя (кроме C#) сделать this = new X();)mutable поля - их могут менять даже const методы.В большинстве языков -- линейное расположение при единичном наследовании -- когда новый членв D дописывается в конец B ( возможно с выравниванием) -> все члены-данные имеютфиксированное смещениеSmalltalk: (вставить картинку 953 фото)Комментарии от Саши, в рукаписных лекциях отсутствуют:/*В С++ не наследуются конструкторы, деструктор и операция присваивания.Java - class name extends name-base-class {...}C# - class name: name-base-class {...}В С# и Java нет модификаторов доступа.
Все классы в отличии от С++ имеют общего предка Object (в нем есть много методов, но нет членов-данных).*/С другой стороны множество типов -- есть множество объектовПростой компилируемый язык -- все ТД не пересекаются => для любого объекта данныхсуществует единтсвенный ТД. Но в C, например, разрешаются некоторые приведения.ОбъединенияИногда нужно объединение:С:-> T1union -> T2-> Tkunion y {T1 v1;T2 v2;T3 v3;} y; -- не размеченная, все просто имеют общее расположение в памятиPascal:type vr = recordf1: T1;…fn: Tn;case <имя>: тип ofvalue1: (структура 1);value2: (структура 2);valuem: (структура m);end;-- вариантная запись, “дискриминированная, размеченная” (можно знать типструктур)R: vr; f1|f2|...|fn|<имя>|структура I50Ada:record…case имя:тип ofwhen value1 => структура 1when others => структура m;end;Синтаксис New: New(p, t1, …, tk) -> тип p указывает на вариантную записьtype UPR = ↑VR;p: VR;-> new(p, value), value -- значение <типа> и память выделяется поразмеру, при этом значение в <имя> не присваиваетсянужно P↑.<имя> = value; -> возможно неверно поставитьВ C -- не размеченные объединения -> часто вручную вводили, чтобы объединения начинались сshort -- идентификатора типа, “диспетчеризация по полю типа” -- работаем по switch, согласно тому,какого типа сообщение к нам пришлоAda:разрешаются только размеченные записи с дискриминированиемcase имя_дискриминанта: типа of //не может отсутствовать?, как на PascalPascal?:type word =recordcase WORD_TYPE ofWD_BITS: (bits: parted? array [1..48] of boolean);WD_INT: (i: integer);WD_REAL: (d: real);…end;X: word;X.i := 65536; -> [48] - знаковый битx.bits[17] := 0; -> можно с битами отдельно работатьAda:record word (D: WORD_TYPE) // обязательно как параметр указываемrecordcase D:WORD_TYPE ofwhen …end;-> X:WORD(WD_BITS); -- и только так -> ??? того, что D установлен? корректно ине изменитсяНо никто не гарантирует, что программист правильно напишет обработку через case=> в ООЯП больших case/switch нет, так как должен быть полиморфизм=> не нужна диспетчеризация по типу=> объединений тоже нет -- все уходит в наследование[постоянная часть -- base_class, вариантивная часть -- в наследников]51Анопя? теориятип -- некоторое множество объетов (потенциально бесконечное)D < B: ∀x∈D => x∈B, D ⋸ B -> в Smalltalk: D -- подкласс, B -- суперклассЕсли T1 ⋸ T2, то T1 ковариантен T2.Совместимость типовx ∈ T1, y ∈ T2 -> x = y, f(T x) => f(y)если T2 ⋸ T1, то можно полагать x=yT1 *p1; T2 *p2; // p2 можно приводить к p1, но не наооборотvoid f(B &x) {...} // внутри по сути 2 типа -- статичный?D y => f(y) // можно, так как D ковариантен Bvoid g(B x) // это B, и динамический -- Dg(y) // при этом тип поменяется; x = y по сутиКласс как область видимостиclass X {...}class Y: X {...}class Y:X {void f() { id = … // используется ??? }}/* как минимум 2 области видимости -- локальная и ??? пространство имен класса*//* сначала ищем в локальном, потом в теле класса -> базовом и т.д.