11.3. Перехват исключений
11.3. Перехват исключений
В языке C++ исключения обрабатываются в предложениях catch. Когда какая-то инструкция внутри try-блока возбуждает исключение, то просматривается список последующих предложений catch в поисках такого, который может его обработать.
Catch-обработчик состоит из трех частей: ключевого слова catch, объявления одного типа или одного объекта, заключенного в круглые скобки (оно называется объявлением исключения), и составной инструкции. Если для обработки исключения выбрано некоторое catch-предложение, то выполняется эта составная инструкция. Рассмотрим catch-обработчики исключений pushOnFull и popOnEmpty в функции main() более подробно:
catch ( pushOnFull ) {
cerr "trying to push value on a full stack ";
return errorCode88;
}
catch ( popOnEmpty ) {
cerr "trying to pop a value on an empty stack ";
return errorCode89;
}
В обоих catch-обработчиках есть объявление типа класса; в первом это pushOnFull, а во втором – popOnEmpty. Для обработки исключения выбирается тот обработчик, для которого типы в объявлении исключения и в возбужденном исключении совпадают. (В главе 19 мы увидим, что типы не обязаны совпадать точно: обработчик для базового класса подходит и для исключений с производными классами.) Например, когда функция-член pop() класса iStack возбуждает исключение popOnEmpty, то управление попадает во второй обработчик. После вывода сообщения об ошибке в cerr, функция main() возвращает код errorCode89.
А если catch-обработчики не содержат инструкции return, с какого места будет продолжено выполнение программы? После завершения обработчика выполнение возобновляется с инструкции, идущей за последним catch-обработчиком в списке. В нашем примере оно продолжается с инструкции return в функции main(). После того как catch-обработчик popOnEmpty выведет сообщение об ошибке, main() вернет 0.
int main() {
iStack stack( 32 );
try {
stack.display();
for ( int x = 1; ix
Говорят, что механизм обработки исключений в C++
не возобновляется с того места, где оно было возбуждено. В нашем
примере управление не возвращается в функцию-член pop(), возбудившую исключение.
11.3.1. Объекты-исключения
Объявлением исключения в catch-обработчике
могут быть объявления типа или объекта. В каких
случаях это следует делать? Тогда, когда необходимо
получить значение или как-то манипулировать объектом,
созданным в выражении throw. Если классы исключений спроектированы
так, что в объектах-исключениях при возбуждении сохраняется
некоторая информация и если в объявлении исключения фигурирует
такой объект, то инструкции внутри catch-обработчика могут
обращаться к информации, сохраненной в объекте выражением throw.
Изменим реализацию класса исключения
pushOnFull, сохранив в объекте-исключении то
значение, которое не удалось поместить в стек.
Catch-обработчик, сообщая об ошибке, теперь будет
выводить его в cerr. Для этого мы сначала модифицируем
определение типа класса pushOnFull следующим образом:
// новый класс исключения:
// он сохраняет значение, которое не удалось поместить в стек
class pushOnFull {
public:
pushOnFull( int i ) : _value( i ) { }
int value { return _value; }
private:
int _value;
};
Новый закрытый член _value содержит число, которое не удалось поместить в стек. Конструктор принимает значение типа int и сохраняет его в члене _data. Вот как вызывается этот конструктор для сохранения значения из выражения throw:
void iStack::push( int value )
{
if ( full() )
// значение, сохраняемое в объекте-исключении
throw pushOnFull( value );
// ...
}
У класса pushOnFull появилась также новая функция-член value(), которую можно использовать в catch-обработчике для вывода хранящегося в объекте-исключении значения:
catch ( pushOnFull eObj ) {
cerr "trying to push value "eObj.value()
"on a full stack ";
}
Обратите внимание, что в объявлении исключения в catch-обработчике фигурирует объект eObj, с помощью которого вызывается функция-член value() класса pushOnFull.
Объект-исключение всегда создается в точке возбуждения, даже если выражение throw – это не вызов конструктора и, на первый взгляд, не должно создавать объекта.
Например:
enum EHstate { noErr, zeroOp, negativeOp, severeError };
enum EHstate state = noErr;
int mathFunc( int i ) {
if ( i == 0 ) {
state = zeroOp;
throw state; // создан объект-исключение
}
// иначе продолжается обычная обработка
}
В этом примере объект state не используется в качестве объекта-исключения. Вместо этого выражением throw создается объект-исключение типа EHstate, который инициализируется значением глобального объекта state. Как программа может различить их? Для ответа на этот вопрос мы должны присмотреться к объявлению исключения в catch-обработчике более внимательно.
Это объявление ведет себя почти так же, как объявление формального параметра. Если при входе в catch-обработчик исключения выясняется, что в нем объявлен объект, то он инициализируется копией объекта-исключения. Например, следующая функция calculate() вызывает определенную выше mathFunc(). При входе в catch-обработчик внутри calculate() объект eObj инициализируется копией объекта-исключения, созданного выражением throw.
void calculate( int op ) {
try {
mathFunc( op );
}
catch ( EHstate eObj ) {
// eObj - копия сгенерированного объекта-исключения
}
}
Объявление исключения в этом примере напоминает передачу параметра по значению. Объект eObj инициализируется значением объекта-исключения точно так же, как переданный по значению формальный параметр функции – значением соответствующего фактического аргумента. (Передача параметров по значению рассматривалась в разделе 7.3)
Как и в случае параметров функции, в объявлении исключения может фигурировать ссылка. Тогда catch-обработчик будет напрямую ссылаться на объект-исключение, сгенерированный выражением throw, а не создавать его локальную копию:
void calculate( int op ) {
try {
mathFunc( op );
}
catch ( EHstate &eObj ) {
// eObj ссылается на сгенерированный объект-исключение
}
}
Для предотвращения ненужного копирования больших объектов применять ссылки следует не только в объявлениях параметров типа класса, но и в объявлениях исключений того же типа.
В последнем случае catch-обработчик сможет модифицировать объект-исключение. Однако переменные, определенные в выражении throw, остаются без изменения. Например, модификация eObj внутри catch-обработчика не затрагивает глобальную переменную state, установленную в выражении throw:
void calculate( int op ) {
try {
mathFunc( op );
}
catch ( EHstate &eObj ) {
// исправить ошибку, вызвавшую исключение
eObj = noErr; // глобальная переменная state не изменилась
}
}
Catch-обработчик переустанавливает eObj в noErr после исправления ошибки, вызвавшей исключение. Поскольку eObj – это ссылка, можно ожидать, что присваивание модифицирует глобальную переменную state. Однако изменяется лишь объект-исключение, созданный в выражении throw, поэтому модификация eObj не затрагивает state.
Более 800 000 книг и аудиокниг! 📚
Получи 2 месяца Литрес Подписки в подарок и наслаждайся неограниченным чтением
ПОЛУЧИТЬ ПОДАРОКЧитайте также
10.6.4. Перехват сигналов: sigaction()
10.6.4. Перехват сигналов: sigaction() Наконец мы готовы взглянуть на функцию sigaction(). Эта функция сложна, и мы намеренно опускаем множество деталей, которые предназначены для специального использования. Стандарт POSIX и справочная страница sigaction(2) предоставляют все подробности,
12.2.3. Перехват сигналов
12.2.3. Перехват сигналов Вместо использования функции signal() (чья семантика в процессе эволюции стала неправильной) POSIX-программы регистрируют обработчики сигналов с помощью sigaction().#include <signal.h>int sigaction(int signum, struct sigaction *act, struct sigaction *oact);Этот системный вызов устанавливает
10.7.1. Перехват соединения
10.7.1. Перехват соединения Вспомним полный цикл соединения с FTP-сервером и передачи файлов:1. Соединение с сервером.2. Авторизация.3. Запрос на скачивание файлов.4. Сервер открывает порт и сообщает его клиенту.5. Клиент подключается к указанному порту и получает или передает
14.5.4. Перехват соединения
14.5.4. Перехват соединения Атака на компьютеры с помощью перехвата соединения была первый раз применена еще несколько десятков лет назад, и до сих пор единственным эффективным методом борьбы с ней является использование шифрования пакетов.Когда компьютеры по протоколу TCP
Перехват сигналов
Перехват сигналов Вы можете использовать встроенную в bash программу trap для перехвата сигналов в своих программах. Это хороший способ изящно завершать работу программы. Например, если пользователь, когда ваша программа работает, нажмет CTRL-C — программе будет отправлен
14.1.2. Перехват вывода программы
14.1.2. Перехват вывода программы Простейший способ перехватить информацию, выведенную программой, — заключить команду в обратные кавычки, например:listing = `ls -l` # Одна строка будет содержать несколько строчек (lines).now = `date` # "Mon Mar 12 16:50:11 CST 2001"Обобщенный ограничитель %x
Обработка исключений
Обработка исключений Ввиду того, что теперь метод Accelerate() может генерировать исключение, вызывающая сторона должна быть готова обработать такое исключение. При вызове метода, способного генерировать исключение, вы должны использовать блок try/catch. Приняв исключение, вы
11.3.4. Перехват всех исключений
11.3.4. Перехват всех исключений Иногда функции нужно выполнить определенное действие до того, как она завершит обработку исключения, даже несмотря на то, что обработать его она не может. К примеру, функция захватила некоторый ресурс, скажем открыла файл или выделила память
Типы исключений
Типы исключений Может появиться три типа исключений.* Ошибки SQL - т. е. сообщения SQL, имеющие отрицательное значение SQLCODE.* Внутренние ошибки Firebird, которые имеют отношение к конкурирующему взаимодействию, данным, метаданным и условиям окружения. У них есть девяти- символьный
26.3.1. Перехват сигналов и выполнение действий
26.3.1. Перехват сигналов и выполнение действий А теперь создадим сценарий, выполняющий подсчет итераций до тех пор, пока пользователь не нажмет комбинацию клавиш [Ctrl+C] (сигнал 2). После этого сценарий отобразит сообщение, содержащее номер текущей итерации цикла.В этом
Источники исключений
Источники исключений Исключения можно классифицировать, разделив их на категории.Определение: исключительные ситуацииИсключения могут возникать при выполнении программы r в результате следующих ситуаций.1 Попытка квалифицированного вызова a.f и обнаружение, что a = Void.2
Глава 11 Перехват сеанса
Глава 11 Перехват сеанса В этой главе обсуждаются следующие темы: • Основные сведения о перехвате сеанса • Популярные инструментальные средства перехвата сеанса • Исследование атак типа MITM в зашифрованных соединениях · Резюме · Конспект · Часто задаваемые вопросы
Перехват
Перехват Одним из наиболее мощных средств в борьбе с преступлениями, диверсиями и мятежами является возможность перехватывать письменные и устные коммуникации. Именно эту привилегию ФБР отстаивает особенно рьяно.Перехват давно известен в американской истории. В 1624