Здравствуйте, a111, Вы писали:
A>ммм понятно A>А делфи через SEH работает с исключениями? A>Просто там как-то проще. В С++ долго разбирался и то, не до конца разобрался с ними.
Смотри сюда — первоначальный ликбез
Структурная обработка исключений (SEH) реализована и в Visual C++.NET 2003 и в C++ Builder 6 как расширение стандартного С++. Поддержка SEH обеспечивается операционной системой Windows, поэтому программы, в которых используется SEH, непереносимы. Кроме того, при структурной обработке исключений не выполняется вызов деструкторов — это наиболее важное отличие SEH от стандартного механизма. Поэтому Microsoft не рекомендует смешивать стандартные и структурные исключения в одной программе.
Структурная обработка исключений предоставляет две возможности: обработку исключений try/except и обработку завершения try/finally. Обработка завершения проще, поэтому начнем с нее. В системе Visual C++.NET 2003 синтаксис обработчика завершения выглядит так:
__try { } // защищенный блок__finally { } // блок завершения
Ключевые слова __try и __finally пишутся с двумя подчеркиваниями — обычно в системе Visual C++.NET 2003 так обозначаются все расширения стандартного С++.
Обработчик завершения гарантирует, что блок завершения будет выполнен при любой попытке выхода из защищенного блока — независимо от способа выхода. Выход из __try-блока осуществляется одним из следующих способов:
1. нормальное выполнение всех операторов блока от начала до конца;
2. возникновение исключения во время выполнения операторов блока;
3. выполнение одного из операторов перехода (break, continue, goto, return), хотя этого Джеффри Рихтер [49] рекомендует избегать.
Поведение программы после выполнения финального блока зависит от способа выхода из __try-блока. Если в финальном блоке нет никаких операторов перехода, и он выполняется до конца, то далее в соответствии со способом выхода из защищенного блока:
1. выполняются операторы после финального блока;
2. выполняются операторы после финального блока;
3. выполняется оператор перехода, который вызвал выход из защищенного блока.
Синтаксис обработчика исключений выглядит так:
__try { } // защищенный блок__except (фильтр)
{ }
// блок обработки исключения
Обратите внимание, что в SEH после защищенного блока следует единственный обработчик, — либо обработчик завершения, либо обработчик исключения. Несколько обработчиков писать нельзя, и тем более нельзя писать несколько разных обработчиков. Однако разрешается конструкцию try/finally вкладывать в try/except и наоборот, и уровень вложенности не ограничен. Правда, в этом случае существует опасность «запутаться» в порядке выполнения блоков __except и __finally.
При нормальном ходе выполнения программы (когда исключения не возникает) после выполнения операторов защищенного блока блок-обработчик пропускается, и программа продолжает работу со следующего после него оператора. А вот если при выполнении операторов защищенного блока возникло исключение, то обработка его зависит от фильтра. Фильтр — это выражение (в том числе и вызов функции), которое должно принимать одно из трех возможных значений:
Очень часто эти константы прописываются в качестве фильтра непосредственно. Только последний вариант означает собственно обработку исключения: выполняются операторы блока обработки, после чего управление передается на первый оператор после него.
Если результат вычисления фильтра равен первой константе, то исключение отклоняется (exception is dismissed). Код в обработчике прерываний никогда не выполняется. Управление возвращается в точку возникновения прерывания и делается попытка снова выполнить ту же инструкцию, которая вызвала исключение.
На первый взгляд поведение не совсем логичное, ведь снова возникнет исключение. Однако не будем забывать, что фильтр – это выражение. Это означает, что на месте фильтра может быть прописано несколько выражений через запятую. В этих выражениях можно исправить причину, вызвавшую исключение. Если необходимо выполнить более сложную работу, то в качестве фильтра может быть прописан вызов функции. Эта функция может получить в качестве параметров любые переменные из защищенного блока, выполнить с ними нужную работу и возвратить константу EXCEPTION_CONTINUE_EXECUTION в качестве результата. Например, если произошло деление на ноль, то функция может изменить значение делителя, и программа сможет «хромать» дальше.
Фильтр EXCEPTION_CONTINUE_SEARCH по своему действию похож на оператор throw без аргумента, то есть «отправляет исключение дальше». Код в обработчике с таким фильтром не выполняется никогда.
Генерация программных исключений выполняется функцией Windows API RaisException(), которую мы рассматривать не будем — подробное изучение SEH в нашу задачу не входит. Однако на одном моменте нужно остановиться. Чем хорошо SEH, так это возможностью «отловить» аппаратные исключения и точно их идентифицировать, естественно, с помощью функции API
DWORD GetExceptCode();
Функция возвращает идентификатор типа исключения, которые определены в файле WinBase.h. Но подключать надо заголовок windows.h. В табл. 4.1 представлены некоторые из этих идентификаторов.
Таблица 4.1. Аппаратные исключения
Значение Описание
EXCEPTION_ACCESS_VIOLATION //Попытка обратиться к «чужой» памяти
EXCEPTION_FLT_DIVIDE_BY_ZERO //Деление на ноль дробных чисел
EXCEPTION_FLT_OVERFLOW //Переполнение для дробных чисел
EXCEPTION_INT_DIVIDE_BY_ZERO //Деление на ноль для целых чисел
EXCEPTION_INT_OVERFLOW //Переполнение для целых чисел
EXCEPTION_STACK_OVERFLOW //Переполнение стека
В составе Windows API реализованы и другие функции, используемые в SEH. Останавливаться подробно мы на этом не будем, так как это не входит в нашу задачу. В справочной системе Visual C++.NET 2003 прописан пример, в котором модифицированы операторы ввода/вывода (листинг 4.22).
//Листинг 4.22. Структурная обработка исключений
// exceptions_try_except_Statement.cpp
// Пример try-except и try-finally #include <iostream>
#include <windows.h> // для EXCEPTION_ACCESS_VIOLATIONusing std::cout;
using std::endl;
// функция-филтрint filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
cout<<"in filter."<< endl;
if (code == EXCEPTION_ACCESS_VIOLATION) {
cout<<"caught AV as expected."<<endl;
return EXCEPTION_EXECUTE_HANDLER; // если авария
}
else {
cout<<"didn't catch AV, unexpected."<< endl;
return EXCEPTION_CONTINUE_SEARCH; // если нет аварии
};
}
int main()
{ int* p = 0x00000000; // специально-нулевой указатель
cout<<"hello"<< endl;
__try{
cout<<"in try 1"<< endl;
__try{
cout<<"in try 2"<< endl;
*p = 13; // access violation
}__finally{
cout<<"in finally. termination: "<< endl;
cout<<(AbnormalTermination() ? "\tabnormal" : "\tnormal")<< endl;
}
}__except(filter(GetExceptionCode(), GetExceptionInformation())){
cout<<"in except"<< endl;
}
cout<<"world"<< endl;
}
Программа специально содержит ошибку (нулевой указатель), чтобы показать обработку возникающего исключения по нарушению доступа к памяти (access violation). Демонстрируется также обязательное выполнение финального блока, несмотря на исключение. Программа выводит на экран
hello
in try 1
in try 2
in filter.
caught AV as expected.
in finally. termination:
abnormal
in except
world
SEH очень подробно описана у Джеффри Рихтера.
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Добрый день!
При трасситовке встроенный отладчик не дает пройти дальше строки записи по нулевому адресу.
При запуске без отладки, приложение закрывается с ошибкой.
Что я сделал не так?
//Visual Studio 2005, дефолтное пустое Win32 приложение.try
{
int *i=0;
*i=2;
}
catch( ... )
{
MessageBox(0,"Ex","Ex",0);
}
Здравствуйте, a111, Вы писали:
A>Добрый день! A>При трасситовке встроенный отладчик не дает пройти дальше строки записи по нулевому адресу. A>При запуске без отладки, приложение закрывается с ошибкой. A>Что я сделал не так? A>
A>//Visual Studio 2005, дефолтное пустое Win32 приложение.
A>try
A>{
A> int *i=0;
A> *i=2;
A>}
A>catch( ... )
A>{
A> MessageBox(0,"Ex","Ex",0);
A>}
A>
Механизм стандартных исключений в С++ не работает с аварийными исключениями операционнойт системы и компьютера. Для этого нужно использовать SEH (в windows)
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re: Почему не обрабатывается исключение:
От:
Аноним
Дата:
24.09.06 15:45
Оценка:
Потому что catch ловит то, что было выброшено с помошью throw.
Здравствуйте, a111, Вы писали:
A>Добрый день! A>При трасситовке встроенный отладчик не дает пройти дальше строки записи по нулевому адресу. A>При запуске без отладки, приложение закрывается с ошибкой. A>Что я сделал не так? A>
A>//Visual Studio 2005, дефолтное пустое Win32 приложение.
A>try
A>{
A> int *i=0;
A> *i=2;
A>}
A>catch( ... )
A>{
A> MessageBox(0,"Ex","Ex",0);
A>}
A>
Потому, что это UB. Компилятор может (1) выкинуть исключение, (2) не выкинуть исключение, (3) отформатировать жесткий диск, (4) не отформатировать жесткий диск... всё, что ему в его пустую голову взбредет.
Если тебе очень-очень-очень хочется обрабатывать такие ситуации, изучай SEH.
Здравствуйте, a111, Вы писали: A>ммм понятно A>А делфи через SEH работает с исключениями? A>Просто там как-то проще. В С++ долго разбирался и то, не до конца разобрался с ними.
Смотри книгу Рихтера. Там в паре глав это подробно расписано.