Ответы на ваши вопросы во многом зависят от того, на каком языке мы говорим.
C вообще не имеет исключений , хотя существуют собственные языковые расширения.
C ++ имеет способ «выбросить» произвольный объект в любой точке вашего кода и «поймать» его где-нибудь выше стек вызовов.
C # имеет способ «выбросить» объекты, полученные из System.Exception
, а также «поймать» те, которые находятся выше в стеке. Кроме того, я думаю, что среда выполнения .NET сообщает о некоторых проблемах при создании самого исключения.
- Что является исключением? Какова его самая низкоуровневая композиция в памяти? В .NET я могу думать об этом как о некотором экземпляре объекта некоторого типа исключения. В родном мире, из чего он сделан? Некоторые структуры данных?
В C ++ это просто произвольный объект, который был создан как другие объекты в коде:
throw 42; // throws an int object
throw "blah"; // throws a char[5] object
throw std::string("arg!"); // throws a std::string object
throw my_type(42); // throws a my_type object
throw std::exception("doh!"); // throws a std::exception object
Соответствие брошенных исключений фразам catch
очень похоже на сопоставление перегруженных функций. (Большое отличие состоит в том, что фразы catch для упорядочены . То есть, первый из найденных совпадений "победит" и поймает объект. Однако перегруженные функции всегда должны обеспечивать однозначно лучшее совпадение.)
- Кто создает исключение, если исключение явно не выдается программистом, как показано в следующем коде? Является ли это частью поддержки, которую обеспечивает определенная языковая среда выполнения?
В C ++ исключения почти могут быть выброшены только из кода. Это может быть ваш собственный код, чужой код, код какой-то библиотеки или код стандартной библиотеки. Но обычно где-то должен быть оператор throw
. Есть несколько исключений (без каламбура), например, std::bad_alloc
, сгенерированный new
(который, вероятно, выдается из оператора throw
в коде, но я думаю, что это не обязательно) и std::bad_cast
, брошенный из dynamic_cast<>
. (Кроме того, следующий стандарт, C ++ 1x, ожидаемый в следующем году, разрешает исключениям каким-то образом пересекать границы потоков, что, вероятно, требует от разработчиков стандартной библиотеки найти способ сохранить исключение в одном потоке и повторно выбросить его из другого. Но я Я довольно смутно от этого.)
SomeException e = new SomeException(); throw e;
В C ++ вы можете , но вы редко когда-либо захотите это бросить указатели . Вы либо делаете
SomeException e; throw e;
или
throw SomeException();
- Какая рабочая парадигма исключения? Правда ли, что когда происходит какая-либо ошибка, во время выполнения языка создается экземпляр соответствующей структуры / типа данных, представляющий подробности ошибки?
Есть несколько мест, где стандартная библиотека C ++ генерирует исключения, но кроме этого я могу думать только о двух вышеупомянутых функциях (плюс одна в C ++ 1x), где среда выполнения генерирует исключения "сама".
- Как мы можем знать все возможные неожиданные ситуации во время выполнения и, таким образом, создавать достаточно структур / типов данных исключений для их представления?
Обычно в C ++ выбрасываются только объекты классов, производных от std::exception
, хотя я сталкивался с кодом, который использовал собственную иерархию классов исключений, которая не была внедрена в std::exception
. Проблема с иерархией исключений в стандартной библиотеке заключается в том, что ее классы наследуются не виртуально друг от друга, что делает невозможным создание собственной иерархии исключений, скрывающей ту из стандартной библиотеки с использованием множественного наследования. (Например, ваш собственный тип исключения OutOfRange
, который наследуется от std::out_of_range
, и базовый класс вашего исключения MyException
, который наследуется от std::exception
.)
В C ++ способ обработки исключений в основном основан на следующих принципах:
- Пишите код таким образом, чтобы он был защищен от исключений, возникающих в любой момент. Используйте RAII и другие методы для достижения этой цели.
- Ловите исключения только в тех местах, где вы можете что-то с ними сделать.
- Бросать исключения только в исключительных случаях.Не используйте их для контроля потока.(Исключения C ++ были разработаны для того, чтобы поставщики могли их реализовать, чтобы минимизировать издержки в неисключительном случае за счет исключительного случая.)