C builder если ошибка то

Наиболее кардинальный путь борьбы с исключениями это отлавливание и обработка их с помощью блоков try … catch. Синтаксис этих блоков следующий:

try
{
Исполняемый код
}
catch(TypeToCatch)
{
Код, исполняемый в случае ошибки
}

Операторы блока catch представляют собой обработчик исключения. Параметр TypeToCatch может быть или одним из целых типов (int, char и т.п.), или ссылкой на класс исключения, или многоточием, что означает обработку любых исключений. Остановимся на случае, когда параметр является ссылкой на класс исключений.

Операторы обработчика выполняются только в случае генерации в операторах блока try исключения типа, указанного в заголовке catch. После блока try может следовать несколько блоков catch для разных типов исключений. Таким образом, в обработчиках catch можно предпринять какие-то действия: известить пользователя о возникшей проблеме и подсказать ему пути ее решения, принять какие-то меры к исправлению ошибки (например, при переполнении заслать в результат очень большое число соответствующего знака) и т.д. Наиболее ценным является то, что можно определить тип сгенерированного исключения и дифференцированно реагировать на различные исключительные ситуации. Причем перехват исключения блоком catch приводит к тому, что это исключение далее не обрабатывается стандартным образом, т.е. пользователю не предъявляется окно с непонятными ему английскими текстами.

Пусть в приложении имеется два окна редактирования Edit1 и Edit2, в которых пользователь вводит действительные числа типа float. Приложение должно разделить их одно на другое. При этом возможен ряд ошибок: пользователь может ввести в окно символы, не преобразуемые в целое число, может ввести слишком большое число, может ввести вместо делителя нуль, результат деления может быть слишком большим для типа float. Следующий код отлавливает все эти ошибки:

float А;
try
{
A = StrToFloat(Edit1->Text) / StrToFloat(Edit2->Text);
}
catch(EConvertError&)
{
Application->MessageBox("Вы ввели ошибочное число", "Повторите ввод", MB_OK);
}
catch(EZeroDivide&)
{
Application->MessageBox ("Вы ввели нуль", "Повторите ввод", MB_OK);
}
catch(EOverflow&)
{
Application->MessageBox ("Переполнение", "Ошибка вычислений", MB_OK);
if(StrToHloat(Edit1->Text) * StrToFloat(Edit2->Text) >= 0)
А = 3.4E38;
else А = -3.4E38;
}

Если пользователь ввел неверное число (например, по ошибке нажал не цифру, а какой-то буквенный символ), то при выполнении функции StrToFloat возникнет исключение класса EConvertError. Соответствующий обработчик исключения сообщит пользователю о сделанной ошибке и посоветует повторить ввод. Аналогичная реакция последует на ввод пользователем в качестве делителя нуля (класс исключения EZeroDivide). Если возникает переполнение, то соответствующий блок catch перехватывает исключение, сообщает о нем пользователю и исправляет ошибку: заносит в результат максимально возможное значение соответствующего знака.

Поскольку исключения образуют иерархию, можно обрабатывать сразу некоторую совокупность исключений, производных от одного базового исключения. Для этого надо в заголовке блока catch указать имя этого базового исключения. Например, исключения EZeroDivide (целочисленное деление на нуль), EOverflow (переполнение при целочисленных операциях), EInvalidArgument (выход числа за допустимый диапазон) и некоторые другие являются производными от класса исключений EMathError. Поэтому все их можно отлавливать с помощью одного блока catch, например, такого:

catch(EMathError&)
{
Application->MessageBox("Ошибка вычислений", "Повторите ввод", MB_OK);
}

Правда, в этом случае не конкретизируется причина прерывания исключений. Однако такая конкретизация возможна, если воспользоваться свойствами исключений. Все исключения имеют свойство Message, которое представляет собой строку, отображаемую пользователю при стандартной обработке исключений.

Чтобы воспользоваться свойствами исключений, надо в заголовке блока catch не только указать тип исключения, но и создать временный указатель на объект этого типа. Тогда через имя этого объекта можно получить доступ к его свойствам. Ниже приведен пример использования свойств исключений при перехвате исключений, наследующих классу EMathError:

catch(EMathErrorS E)
{
AnsiString S = "Ошибка вычислений : ";
if(E.Message == "EZeroDivide") S += "деление на нуль";
if(E.Message == "EOverflow") S += "переполнение";
if(E.Message == "EInvalidArgument") S += "недопустимое число";
Application->MessageBox(S.c_str(), "Повторите ввод", MB_OK);
}

Вводимое в этом операторе имя ссылки на исключение E носит сугубо локальный характер и вводится только для того, чтобы можно было сослаться на свойство Message по имени объекта исключения.

Если в заголовке блока catch указано многоточие, то этот блок перехватит любые исключения: 

catch(...)
{
ShowMessage("Произошла ошибка.");
}

Блок catch(…) может сочетаться и с другими блоками catch, но в этом случае он должен, конечно, располагаться последним. Поскольку этот блок перехватит все исключения, то все блоки, следующие за ним, окажутся недоступными. C++Builder следит за этим. Если блок catch(…) оказался не последним, то будет выдано компилятором сообщение об ошибке с текстом: «The handler must be last» («Обработчик должен быть последним»).

Следует указать на некоторую опасность применения блока catch(…). Перехват всех исключений способен замаскировать какие-то непредвиденные ошибки в программе, что затруднит их поиск и снизит надежность работы.

Блоки try…catch могут быть вложенными явным или неявным образом. Примером неявной вложенности является блок try…catch, в котором среди операторов раздела try имеются вызовы функций, которые имеют свои собственные блоки try…catch. При генерации исключения сначала ищется соответствующий ему обработчик в том блоке try…catch, в котором создалась исключительная ситуация. Если соответствующий обработчик не найден, поиск ведется в обрамляющем блоке try…catch (при наличии явным образом вложенных блоков) и т.д. Если в данной функции обработчик не найден или вообще в ней отсутствуют блоки try…catch, то поиск переходит на следующий уровень в блок, из которого была вызвана данная функция. Этот поиск продолжается по всем уровням. И только если он закончился безрезультатно, выполняется стандартная обработка исключения, заключающаяся, как уже было сказано, в выдаче пользователю сообщения о типе исключения.

Как только блок catch, соответствующий данному исключению, найден и выполнен, объект исключения разрушается и управление передается оператору, следующему за соответствующим блоком try…catch.

Если исключение не перехвачено ни одним обработчиком в функциях, можно обработать его на уровне приложения. Для этого предусмотрены события OnException компонента Application самого приложения. Обработчик этих событий можно ввести в приложение следующим образом. Допустим можно назвать этот обработчик MyException. Тогда в заголовочный файл приложения надо добавить его объявление:

void __fastcall MyException(TObject *Sender, Exception *E);

В файл вашего модуля надо внести реализацию обработчика:

void __fastcall TForm1::MyException(TObject *Sender, Exception *E)
{
// операторы обработки
}

Осталось указать приложению на функцию MyException как на обработчик события OnException. Можно это сделать, включив, например, в обработку события формы OnCreate оператор:

Applioation->OnException = MyException;

Обработчик не перехваченных ранее исключений готов. Осталось только наполнить его операторами, сообщающими пользователю о возникших неполадках и обеспечивающими дальнейшую работу программы. К функции MyException приложение будет обращаться, если было сгенерировано исключение и ни один блок catch его не перехватил. В функцию передается указатель Е на объект класса Exception. Этот объект является сгенерированным исключением, а класс Exception базовый класс всех исключений.

Простейшая обработка исключения могла бы производиться функцией ShowException, обеспечивающей отображение информации об исключении:

Application->ShowException(E);

В заголовке окна пишется имя приложения, а текст содержит описание причины генерации исключения. Основным недостатком функции являются сообщения на английском языке, что вряд ли порадует пользователей приложения. Поэтому лучше сделать собственные сообщения. При этом для определения истинного класса сгенерированного исключения можно воспользоваться методом ClassName. Тогда обработчик события OnException может иметь, например, следующий вид:

void __fastcall TForm1::MyException(TObject *Sender, Exception *E)
{
AnsiString S = "Ошибка вычислений : ";
if(String(E->ClassName{}) == "EZeroDivide") S += "деление на нуль";
if(String(E->ClassName()) == "EOverflow") S += "переполнение";
if(String(E->ClassName()) == "EInvalidArgument") S += "недопустимое число";
if(String(E->ClassName()) == "EConvertError") S += "ввели недопустимое число";
Application->MessageBox(S.c_str(),"Повторите ввод",MB_OK);
}

Табаков Юрий

Табаков Юрий

Программист

Автор и редактор проекта CuBook.PRO. Главная задача, которую я ставлю перед собой – донести до начинающих программистов удобочитаемый материал. Буду рад выслушать замечания и предложения. Не забываем ставить оценки и делать репосты =)

Лучший ответ Сообщение было отмечено как решение

Решение

Цитата
Сообщение от Programmer.
Посмотреть сообщение

Добрый вечер форум

Может кто нит обияснит что такое try, catch(…)

Принципы обработки исключений
В С++ исключение — это объект. Хотя обычно говорят об исключительной ситуации в программе, такая точка зрения мало что дает, так как с ситуацией сделать ничего нельзя. Поэтому в С++ при возникновении исключительной ситуации программа должна генерировать объект-исключение. Собственно, сама генерация объекта-исключения и создает исключительную ситуацию. Такой подход очень удобен, так как с объектами, в отличие от ситуаций, мы можем много чего делать. Например, объект-исключение можно объявить как обычную переменную, передать его как параметр любым из возможных способов или возвратить в качестве результата. Можно объявлять массивы исключений или включать объекты-исключения в качестве полей в другие классы. В дальнейшем мы будем использовать термин «исключение», понимая под этим объект-исключение.
Общая схема обработки исключений такова: в одной части программы, где обнаружена аварийная ситуация, исключение порождается; другая часть программы контролирует возникновение исключения, перехватывает и обрабатывает его. В С++ есть три зарезервированных слова: try (контролировать), catch (перехватывать), throw (порождать), — которые и используются для организации процесса обработки исключений.
Генерация исключений
Генерируется исключение оператором throw (см. п. 15.1 в [1]), который имеет следующий синтаксис
throw выражение_генерации_исключения;
Выражение генерации исключения на практике означает либо константу, либо переменную некоторого типа. Тип объекта-исключения может быть любым, как встроенным, так и определяемым программистом. Например:

C++
1
2
3
4
throw 7;
throw "Ошибка: деление на ноль!";
throw Message[i];
throw M_PI;

В первом случае объект-исключение — это целая константа, которая может быть условным номером-кодом ошибки. В общем случае этот код ошибки может вычисляться, например:

Выражение, конечно, может быть не только целочисленным.
Второй вариант — это символьная константа, которая фактически является сообщением об ошибке. Все сообщения об ошибках могут быть записаны в массиве, например:

C++
1
string Message[326];

Тогда в третьем варианте объект-исключение тоже представляет собой строку — сообщение об ошибке. В последнем примере в качестве объекта используется дробная константа — число *.
Программист может и сам определить собственный тип объекта-исключения, объявив новый класс, например:

C++
1
2
3
4
class NegativeArgument{};
NegativeArgument exeption;
if (x>0) double t = x/sqrt(x);
else throw exeption;

Пустые классы неожиданно пригодились! Однако объявлять переменную совсем не обязательно, можно обойтись и без этого, например:

C++
1
throw NegativeArgument();

Здесь в качестве выражения генерации исключения мы использовали явный вызов конструктора без аргументов, и это наиболее распространенная форма генерации исключения.
Объект-исключение может быть и динамическим, например:

C++
1
throw new NegativeArgument();

Однако в этом случае возникает вопрос об уничтожении объекта-исключения и возврате памяти — неизвестно, в каком месте программы это можно сделать. Лучше не создавать себе проблем и не использовать указатели в качестве параметров блоков catch.
Перехват и обработка исключений
Сгенерировать исключение — это только полдела. Как уже отмечалось, исключение надо перехватить и обработать. Проверка возникновения исключения делается с помощью оператора try, с которым неразрывно связаны одна или несколько блоков обработки исключений — catch. Оператор try объявляет в любом месте программы контролируемый блок, который имеет следующий вид:

C++
1
try { /* контролируемый блок */ }

Контролируемый блок, помимо функции контроля, обладает функциями обычного блока: все переменные, объявленные внутри него, являются локальными в этом блоке и не видны вне его.
После блока try обязательно прописывается один или несколько блоков catch, которые обычно называют обработчиками исключений, или секциями-ловушками. Форма записи секции-ловушки следующая:

C++
1
catch (спецификация_параметра_исключения) { /* блок обработки */}

Спецификация параметра исключения может иметь следующие три формы:
(тип имя)
(тип)
(…)
Тип должен быть одним из допустимых типов исключений — либо встроенным, либо определенным программистом . Первый вариант спецификации означает, что объект-исключение передается в блок обработки, чтобы там его как-то использовать, например, для вывода информации в сообщении об ошибке.
ВНИМАНИЕ
При выполнении оператора throw создается временный объект-исключение, который и передается в секцию-ловушку (см. п.п. 15.1/3 в [1]).
При этом объект-исключение может передаваться в секцию-ловушку любым способом: по значению, по ссылке или по указателю, например:

C++
1
2
3
4
catch (TException e)             // по значению
catch (TException& e)            // по ссылке
catch (const TException& e)      // по константной ссылке
catch (TException *e)            // по по указателю

Однако в отличие от параметров функций, никаких преобразований типов по умолчанию не производится . Это означает, что если в программе написан следующий заголовок обработчика, то попадают в соответствующую ловушку только те исключения, тип которых совпадает с double:

C++
1
catch (double e)                 // по значению

Еще пример:

Этот оператор генерирует исключение целого типа, поэтому будет обрабатываться секцией-ловушкой с заголовком, в котором прописан целый тип исключения, например, одним из следующих способов:

C++
1
2
catch (int e)                    // по значению
catch (int)                      // без передачи информации в секцию-ловушку

Это легко проверить, выполнив следующую простую тестовую программу:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main()
{    try { throw 1;                           // генерация исключения
        }
    catch(unsigned int)
        { cout << "unsigned integer" << endl;
        }
    catch(int)                                // перехватывается здесь
        { cout << "integer" << endl;
        }
    catch(double)
        { cout << "double" << endl;
        }
    return 0;
}

На экране появится слово integer, так как константа 1 по умолчанию имеет тип int.
Первые две формы из приведенных спецификаций параметра исключения предназначены для обработки конкретного типа исключений. Если же на месте спецификации исключения написано многоточие (как в функциях с переменным числом параметров), то такой обработчик перехватывает все исключения.
Работа конструкции try…catch напоминает работу оператора switch. Секции-ловушки похожи на альтернативы case, а блок catch с многоточием соответствует альтернативе default оператора-переключателя. Если в блоке try возникает исключение, то начинается сравнение типа сгенерированного исключения и типов параметров в секциях-ловушках. Выполняется тот блок catch, тип параметра которого совпал с типом исключения. Если такого типа не найдено, выполняется блок catch с многоточием. Если же такого блока в текущем списке обработчиков не обнаруживается, то ищется другой список обработчиков в вызывающей функции. Этот поиск продолжается вплоть до функции main(). Если же и там не обнаружится нужного блока catch, то вызывается стандартная функция завершения terminate() (см. п.п. 15.5.1 в [1]), которая вызывает функцию abort().
Таким образом, очень важен порядок записи секций-ловушек после контролируемого блока. Если в качестве первого обработчика после блока try задан блок catch с параметром-многоточием, то такой обработчик будет обрабатывать все возникающие исключения — до остальных секций-ловушек дело просто не дойдет. Поэтому усвойте следующее простое правило: блок catch с параметром-многоточием всегда должен быть последним. Секция-ловушка с многоточием — это крайняя мера: если уж мы в нее попали, то в программе произошло что-то совсем непредусмотренное. Поэтому в такой секции обычно выводят сообщение о непредвиденном исключении и завершают работу программы.



24



Исключения и их стандартная обработка

При работе программы
могут возникать различного рода ошибки:
переполнение, деление на нуль, попытка
открыть несуществующий файл и т.п. В
этих случая, т.е. когда программа не
может выполнить какое-то действие. При
возникновении таких исключительных
ситуаций программа генерирует так
называемое исключение
и выполнение
дальнейших вычислений в данном блоке
прекращается. Исключение — это объект
специального вида, характеризующий
возникшую в программе исключительную
ситуацию. Каждому виду исключения
соответствует свой класс. Объект,
созданный на основе такого класса может
содержать в виде параметров некоторую
уточняющую информацию. Особенностью
исключений является то, что это сугубо
временные объекты. Как только они
обработаны каким-то обработчиком, они
разрушаются.

Если исключение
не перехвачено, то оно обрабатывается
методом Application->HandleException.
Он обеспечивает
стандартную реакцию программы на
большинство исключений — выдачу
пользователю краткой информации в окне
сообщений и уничтожение экземпляра
исключения.

Исключения могут
быть созданы не только автоматически,
т.е. самой программой, но и программистом.

Базовый класс исключений vcl Exception

Все предопределенные
в C++Builder классы исключений являются
прямыми или косвенными наследниками
класса Exception,
объявленного
в модуле SysUtils
и наследующего непосредственно TObject.

Класс
Exception
имеет два
свойства:

Свойство

Тип

Описание

HelpContext

int

Целый
идентификатор экрана контекстно-зависимой
справки. Этот экран справки отображается,
если пользователь, находясь в окне с
сообщением об ошибке, нажимает клавишу
F1. По умолчанию значение равно 0.

Message

System::AnsiString

Строка
сообщения, которая в дальнейшем при
обработке исключения системным
обработчиком отображается в окне
сообщений; устанавливается конструктором
по умолчанию.

Свойство Message
имеет значение
по умолчанию, которое присваивается
при автоматической генерации исключения.
При преднамеренной генерации исключений
их конструкторы, могут задавать значение
свойства Message
в виде переменной типа string
или литеральной константы.

Свойство HelpContext
хранит целый
идентификатор соответствующий экрану
контекстно-зависимой справки. Этот
экран справки отображается, если
пользователь, находясь в окне с сообщением
об ошибке, нажимает клавишу Fl .

По умолчанию
значение свойства HelpContext
равно 0. Это
значение может изменяться некоторыми
конструкторами исключений. Например,
оператор

throw
Exception(«He
хватает исходных данных», 4 );

генерирует
исключение со значением свойства
Message,
равным тексту «Не хватает исходных
данных», и значением свойства HelpContext,
равным 4. При
получении сообщения об этом исключении
пользователь сможет нажать клавишу F1
и получить пояснения, что ему делать в
этом случае. Генерация исключения
осуществляется ключевым словом throw.
Пользователь
может, проанализировав какие-то данные
и обнаружив ошибку, сгенерировать таким
образом собственное исключение, которое
будет затем обработано приложением.

Чтобы свойство
HelpContext
работало,
надо создать соответствующий файл
справки и связать его с приложением,
установив соответствующую опцию Help
file (файл справки) в окне Project Options (опции
проекта) на странице Application (приложение).

Обработка
исключений в блоках
try
… catch

Рассмотрим следующий
пример. В
приложении имеется два окна редактирования
Edit1
и
Edit2,
в которых
пользователь вводит действительные
числа типа float.
Приложение
должно разделить их одно на другое.

Выполняемый код
очень простой:

float
A;

A=StrToFloat(Edit1->Text)/StrToFloat(Edit2->Text);

Если в Edit2
поместить ноль, то после запуска программы
появится сообщение

Если в любом окне
вместе с цифрами закрадется символ, то
появится сообщение

Эти сообщения
предупреждают пользователя о том, что
произошла исключительная ситуация.
Недостатком такого хода выполненеия
программы, во-первых, является ее
завершение, после нажатия кнопки OK,
во-вторых, предложения на английском
языке, что многим пользователям непонятно.

Очевидно, что при
выполнении программы произошла
исключительная ситуация или, как говорят,
исключение. Если бы в программу поступило
сообщение о том, что произошло, то можно
было сделать так, что программа вышла
из исключительной ситуации.

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

Наиболее кардинальный
путь борьбы с исключениями — отлавливание
и обработка их с помощью блоков try
… catch
.
Синтаксис
этих блоков следующий:

try

{

Исполняемый
код в котором возможны исключения

}

catch
(Тип_соответствующего_исключения)

{

Код,
исполняемый в случае ошибки

}

Операторы блока
catch
представляют
собой обработчик исключения. Параметр
Тип_соответствующего_исключения
может быть
или одним из целых типов (int,
char
и т.п.), или
ссылкой на класс исключения, или
многоточием, что означает обработку
любых исключений. Остановимся на случае,
когда параметр является ссылкой на
класс исключений.

Операторы обработчика
выполняются только в случае генерации
в операторах блока try
исключения типа, указанного в заголовке
catch.
После блока
try
может следовать несколько блоков catch
для разных
типов исключений. Таким образом, в
обработчиках catch
можно
предпринять какие-то действия: известить
пользователя о возникшей проблеме и
подсказать ему пути ее решения, принять
какие-то меры к исправлению ошибки
(например, при переполнении заслать в
результат очень большое число
соответствующего знака) и т.д. Наиболее
ценным является то, что вы можете
определить тип сгенерированного
исключения и дифференцированно
реагировать на,различные исключительные
ситуации. Причем перехват исключения
блоком catch
приводит к
тому, что это исключение далее не
обрабатывается стандартным образом,
т.е. пользователю не предъявляется окно
с непонятными ему английскими текстами.

Приведем пример
обработки исключений. Пусть в вашем
приложении имеется два окна редактирования
Edit1
и
Edit2,
в которых
пользователь вводит действительные
числа типа float.
Приложение
должно разделить их одно на другое. При
этомвозможен ряд ошибок: пользователь
может ввести в окно символы, не
преобразуемые в целое число, может
ввести слишком большое число, может
ввести вместо делителя нуль, результат
деления может быть слишком большим для
типа float.
Следующий
код отлавливает все эти ошибки:

float
A;

try

{

A
=
StrToFloat(Edit1->Text)/StrToFloat(Edit2->Text);

}

catch
(EConvertError&)

{

Application->MessageBox
(«Вы
ввели
ошибочное
число«,

«Повторите
ввод»
,
MB_OK) ;

}

catch
(EZeroDivide&)

{

Application->MessageBox
Вы
ввели
ноль«,»Повторите
ввод«,
MB_OK) ;

}

catch
(EOverflow&)

{

Application->MessageBox
Переполнение«,

«Ошибка
вычислений«
,MB_OK) ;

if
(StrToFloat (Edit1->Text) * StrToFloat (Edit2->Text) >= 0)

A
= 3.4
E38;

else
A
= -3.4
E38;

}

Если пользователь
ввел неверное число (например, по ошибке
нажал не цифру, а какой-то буквенный
символ), то при выполнении функции
StrToFloat
возникнет
исключение класса EConvertError.
Соответствующий
обработчик исклюю чения сообщит
пользователю о сделанной ошибке и
посоветует повторить ввод. Аналогичная
реакция последует на ввод пользователем
в качестве делителя нуля (класс исключения
EZeroDivide).
Если возникает
переполнение, то соответствующий блок
catch
перехватывает
исключение, сообщает о нем пользователю
и исправляет ошибку: заносит в результат
максимально возможное значение
соответствующего знака.

Поскольку исключения
образуют иерархию, можно обрабатывать
сразу некоторую совокупность
исключений,производных от одного
базового исключения. Для этого надо в
заголовке блока catch
указать имя
этого базового исключения. Например,
исключения EZeroDivide
(целочисленное
деление на нуль), EOverflow
(переполнение
при целочисленных операциях),
EInvalidArgument
(выход числа
за допустимый диапазон) и некоторые
другие являются производными от класса
исключений EMathError.
Поэтому все
их можно отлавливать с помощью одного
блока catch,
например, такого:

catch
(EMathError&)

{

Application->MessageBox(«Ошибка
вычислений», «Повторите ввод»,
МВ_ОК) ;

}

Правда, в этом
случае не конкретизируется причина
прерывания исключений. Однако такая
конкретизация возможна, если воспользоваться
свойствами исключений. Все исключения
имеют свойство Message,
которое
представляет собой строку, отображаемую
пользователю при стандартной обработке
исключений.

Чтобы
воспользоваться свойствами исключений,
надо в заголовке блока catch
не только
указать тип исключения, но и создать
временный указатель на объект этого
типа. Тогда через имя этого объекта вы
получаете доступ к его свойствам. Ниже
приведен пример использования свойств
исключений при перехвате исключений,
наследующих классу EMathError:

catch
(EMathError& E)

{

AnsiString
S=»
Ошибка
вычислений:»;

if
(E.Message == «EZeroDivide») S+=»
деление
на
нуль«;

if
(E.Message == «EOverflow») S+=»
переполнение«;

if
(E. Message == «EInvalidArgument») S+=»
недопустимое
число«;

Application->MessageBox
(S.c_str (), «
Повторите
ввод«,
MB_OK);

}

Вводимое в этом
операторе имя ссылки на исключение Е
носит сугубо локальный характер и
вводится только для того, чтобы можно
было сослаться на свойство Message
по имени объекта исключения.

Как уже говорилось
выше, если в заголовке блока catch
указано
многоточие, то этот блок перехватит
любые исключения:

catch
(…)

{

ShowMessage(«Произошла
ошибка.»);

}

Блок catch(…)
может сочетаться и с другими блоками
catch,
но в этом
случае он должен, конечно, располагаться
последним. Поскольку этот блок перехватит
все исключения, то все блоки, следующие
за ним, окажутся недоступными. C++Builder
следит за этим. Если блок catch(…)
оказался не
последним, вам будет выдано компилятором
сообщение об ошибке с текстом: «The handler
must be last» «Обработчик должен быть
последним»).

Предупреждение

Следует
указать на некоторую опасность применения
блока catch(…).
Перехват всех исключений способен
замаскировать какие-то непредвиденные
ошибки в программе, что затруднит их
поиск и снизит надежность работы.

Блоки try…catch
могут быть
вложенными явным или неявным образом.
Примером неявной вложенности является
блок try…catch,
в котором
среди операторов раздела try
имеются
вызовы функций, которые имеют свои
собственные блоки try…catch.
При генерации
исключения сначала ищется соответствующий
ему обработчик в том блоке try…catch,
в котором
создалась исключительная ситуация.
Если соответствующий обработчик не
найден, поиск ведется в обрамляющем
блоке try…catch
(при наличии
явным образом вложенных блоков) и т.д.
Если в данной функции обработчик не
найден или вообще в ней отсутствуют
блоки try…catch,
то поиск переходит на следующий уровень
— в блок, из которого была вызвана данная
функция. Этот поиск продолжается по
всем уровням. И только если он закончился
безрезультатно, выполняется стандартная
обработка исключения, заключающаяся,
как уже было сказано, в выдаче пользователю
сообщения о типе исключения. Как только
блок catch,
соответствующий
данному исключению, найден и выполнен,
объект исключения разрушается и
управление передается оператору,
следующему за соответствующим блоком
try…catch.

Если исключение
не перехвачено ни одним обработчиком
в функциях, вы можете обработать его на
уровне приложения. Для этого предусмотрены
события OnException
компонента
Application
— самого
приложения. Обработчик этих событий
можно ввести в ваше приложение следующим
образом. Пусть вы решили назвать этот
обработчик MyException.
Тогда в
заголовочный файл приложения надо
добавить его объявление:

void
__fastcall MyException(TObject *Sender, Exception *E)
;

В
файл вашего модуля надо внести реализацию
обработчика:

void
__fastcall TEorm1::MyException(TObject *Sender, Exception *E)

{

//
операторы
обработки

}

Осталось
указать приложению на вашу функцию
MyException
как на
обработчик события OnException.
Вы можете
это сделать, включив, например, в обработку
события формы OnCreate
оператор:

Application->OnException
=
MyException;

Обработчик не
перехваченных ранее исключений готов.
Осталось только наполнить его операторами,
сообщающими пользователю о возникших
неполадках и обеспечивающими дальнейшую
работу программы. К функции MyException
приложение
будет обращаться, если было сгенерировано
исключение и ни один блок catch
его не
перехватил. В функцию передается
указатель Е
на объект класса Exception.
Этот объект
является сгенерированным исключением,
а класс Exception
— базовый
класс всех исключений. Простейшая
обработка исключения могла бы производиться
функцией ShowException,
обеспечивающей
отображение информации об исключении:

Application->ShowException(E);

В заголовке окна
пишется имя приложения, а текст содержит
описание причины генерации исключения.
Основным недостатком функции являются
сообщения на английском языке, что вряд
ли порадует пользователей вашего
приложения. Поэтому лучше сделать
собственные сообщения. При этом для
определения истинного класса
сгенерированного исключения можно
воспользоваться методом ClassName.
Тогда
обработчик события OnException
может
иметь, например, следующий вид:

void
__fastcall TForm1::MyException(TObject *Sender, Exception *E)

{

AnsiString
S = «
Ошибка
вычислений
«;

if
(String(E->ClassName()) == «EZeroDivide»)

S+=
«
деление
на
нуль«;

if
(String(E->ClassName()) == «EOverflow»)

S+=
«
переполнение«;

if
(String (E->ClassName())==»EInvalidArgument»)

S+=
«
недопустимое
число«;

if(String(E->ClassName())==»EConvertError»)

S+=
«
ввели
недопустимое
число«;

Application->MessageBox(S.c_str(),»Повторите
ввод«,MB_OK);

}

В C++Builder имеется
исключение EAbort,
несколько
отличающееся от рассмотренных ранее.
Генерация этого исключения, как и любых
других, прерывает процесс вычисления.
Но если приложение не отлавливает
соответствующим блоком catch
исключений этого класса, то они попадают
в обработчик TApplication::HandleException
и там, в
отличие от других исключений, разрушаются
без всяких сообщений. Таким образом,
это «молчаливое» прерывание процесса
вычисления, при котором не должно
отображаться диалоговое окно с сообщением
обошибке. Простейший путь генерации
исключения EAbort
— вызов
функции Abort.
Например:

if
(…) Abort( );

Только нельзя
путать две похожие внешне функции: Abort
– генерация
“молчаливого” исключения, и abort
— аварийное
завершение программы. Обычное применение
EAbort
— прерывание
вычислений при выполнении некоторого
условия окончания или условия прерывания
пользователем (например, при нажатии
клавиши Esc или какого-то оговоренного
сочетания клавиш). Функция Abort
прерывает
текущую процедуру и все вызвавшие ее
процедуры, передавая управление на
самый верх. Таким образом, это наиболее
простой выход из глубоко вложенных
процедур. Впрочем, можно при необходимости
перехватить исключение на каком-то
промежуточном уровне, предусмотрев на
нем блок try…catch
и вставив
соответствующий оператор обработки:

catch(EAbort&)

Рассмотрим простой пример

//Простой пример
обработки исключительной ситуации

#include<iostream>

#include<windows>

using
namespace std;

int main(){

SetConsoleOutputCP(1251);

cout<<«Начало«<<endl;

try{//начало
блока
try

cout<<«Внутри
блока
try»<<endl;

throw
10;
//возбуждение
ошибки

cout<<«Эта
инструкция выполнена не будет, ошибка
уже произошла»;

}catch(int
i){//перехват
ошибки

cout<<«Перехвачена
ошибка номер: «<<
i<<endl;

}

return 0;

char z;

cin>>z;

}

В этом прмере ошибка генерируется
всегда, что совсем не характерно для
реального процесса программирования.
Цель этого примера состоит в том, чтобы
показать каким образои можно сгенерировать
и перехватить ошибку.

Глядя на этот пример можно сказать, что
в блоке try,в случае возникновения исключительной
ситуации, операторthrowопределяет объект для передачи в блокcatch,
выполнение блокаtryпрекращается, т.е. остаток блока
игнорируется. Далее выполнение программы
переходит в блокcatch.
Сформированный в блокеtryобъект , в данном случае это число типаintравное 10, передается блокуcatchв качестве параметра. Блоковcatch
может быть несколько, в зависимости
от числа генерируемых исключений. Но у
каждого блокаtryолжен быть хотя бы один блокcatchи наоборот.

Как уже упоминалось, тип
исключительной ситуации должен
соответствен типу, заданному в инструкции
catch.
Например, в предыдущем примере, ее
изменить тип данных в инструкции catch
на double,
то исключительная туация
не будет перехвачена и будет иметь место
ненормальное завершен программы.

Исключительная ситуация
может быть возбуждена не входящей в
блок try
инструкцией,
если сама эта инструкция входит в
функцию, которая вызывается из
блока try.
Например, ниже представлена совершенно
правильная программа:

/*Возбуждение
исключительной ситуации из функции,

находящейся
вне
блока
try
*/

#include
<iostream>

#include<windows>

using
namespace
std;

void
Xtest(int test){

cout
<< «Внутри
функции
Xtest, test равно:
» << test << «n»; if(test)
throw test;

}

int
main (){

SetConsoleOutputCP(1251);

cout
<< «началоn»;

try
{ //
начало
блока
try

cout
<<«Внутри
блока
tryn»;

Xtest(0);

Xtest
(1);

Xtest
(2);

}

catch
(int i) { // перехват
ошибки

cout
<< «перехвачена ошибка номер: «;
cout
<< i
<< «n»;

}

cout
<<
«конец»;

return
0;

}

Следует напомнить, что C++
поддерживает синтаксис языка «С», в
которомfalseзаписывается как 0 , а все, что не ноль
естьtrue.
Именно поэтому в функции возникает
исключение.

Блок try
можно располагать внутри функции. В
этом случае при каждом входе
в функцию обработчик исключительной
ситуации устанавливается снова. Например,

//
Блоки try
и catch
могут находиться не только в функции
main()

#include
<iostream>

using
namespace std;

void
Xhandler(int test){

try
{

if(test)
throw test;

catch(int
i) {

cout
<< «перехвачена ошибка номер:<<i<<endl;

}

}

//=====================

int
main(){

cout<<«началоn»;

Xhandler
(1);

Xhandler
(2);

Xhandler(0);

Xhandler(3);

cout<<«конец»;

return
0;

}

На экран
программа выводит следующее:

начало

Перехвачена
ошибка номер: 1

Перехвачена
ошибка номер: 2

Перехвачена
ошибка номер: 3

конец

В данном
примере обработаны три исключительные
ситуации. После вызова каждой
исключительной ситуации функция
возвращает свое значение. При повторном
вызове функции обработчик исключительной
ситуации устанавлив ется вновь.

Как упоминалось ранее, с
блоком try
можно связать более одной инструкции
catch.
Как правило, так и делается. При этом
каждая инструкция catch
предназначена для перехвата своего
типа исключттельной ситуации

#include<iostream>

#include<windows>

using
namespace
std;

//Можно
перехватывать разные типы исключительных
ситуаций

void
Xhandler(int
test){

try{

if(test)
throw test;

else
throw «Значение
равно
нулю»;

}

catch(int
i) {

cout
<<«Перехвачена
ошибка
номер:
«<<i<<endl;

}

catch(char
*str) {

cout
<<«Перехвачена
строка:
»
<<str << endl;

}

}

//======================

main(){

SetConsoleOutputCP(1251);

cout
<< «началоn»;

Xhandler(1);

Xhandler(2);

Xhandler(0);

Xhandler(3);

cout
<< «конец»;

return
0;

}

На экран
программа выводит следующее:

Как видите, каждая инструкция
catch
перехватывает только
исключительные ситуации соответствующего
ей типа.

Обычно выражения инструкций
catch
проверяются в
том порядке, в кoтopoм
они появляются в программе. Выполняется
только та инструкция, которая совпадает
по типу даниых с исключительной ситуации.
Все оетальные блоки catch
игнорируются.

Исключения
с Builder

Пример для Builder

Создайте форму

с
обработчиком
кнопки

void
__fastcall TForm1::Button1Click(TObject *Sender)

{

float
a;

try{

a=StrToFloat(Edit1->Text)/StrToFloat(Edit2->Text);

}
catch(EConvertError&){

Application->MessageBox(«Вы
ввели
ошибочное
число
«,

«Повторите
ввод»,
MB_OK);

}

catch(EZeroDivide&){

Application->MessageBox(«Вы
ввели
ноль»,

«Повторите
ввод»,
MB_OK);

}

catch(EOverflow&){

Application->MessageBox(«Переполнение»,

«Ошибка
вычислений»,
MB_OK);

if(StrToFloat(Edit1->Text)*StrToFloat(Edit2->Text)>=0)

a=3.4E38;

else
a=-3.4E38;

}

}

//—————————————————————————

Отключите дебаггер. Для
этго войдите в меню Tools/Debugger
Options.
В
появившемся
окне
снимите
флажок
Integrated
debugging.

Лена

Отправлено: 04.10.2006, 12:02

Мастер участка

Группа: Участник
Сообщений: 501

В базе данных есть колонки с типом timestamp (время и дата). Если пользователь вводит не правильно данные в эти колонки (в гриде), то возникает исключение. Как правильно перехватить и обработать такое исключение:
Связь:
ADOQuery -> TDatasetProvider -> TClientDataset -> TDatasource

Для провайдера написала обработчик, но он не срабатывает:

CODE
void __fastcall TDataModule2::DataSetProviderGrupUpdateError(
     TObject *Sender, TCustomClientDataSet *DataSet, EUpdateError *E,
     TUpdateKind UpdateKind, TResolverResponse &Response)
{
 ShowMessage(«Не правильный ввод значения»);
 Response = rrSkip;
}

olegenty

Отправлено: 04.10.2006, 12:31

Ветеран

Группа: Модератор
Сообщений: 2412

typedef void __fastcall (__closure *TFieldNotifyEvent)(TField* Sender);
__property TFieldNotifyEvent OnValidate = {read=FOnValidate, write=FOnValidate};

Description

Write an OnValidate event handler to validate changes made to the data in the field, just before the data is written to the current record buffer. The EditMask property allows validation of the data on a character by character basis while it is being entered by the user. OnValidate allows an application to validate the data as a whole.

Лена

Отправлено: 04.10.2006, 12:48

Мастер участка

Группа: Участник
Сообщений: 501

Написала для нужного поля, никакой реакции. Все равно исключение:

CODE
void __fastcall TDataModule2::ClientDataSetGrupstimeValidate(
     TField *Sender)
{
 ShowMessage(«Не правильный ввод значения»);
 Abort();
}

Admin

Отправлено: 04.10.2006, 15:24

Владимир

Группа: Администратор
Сообщений: 1190

Конечно обычный DBGrid не удобен для
ввода/редактирования значений полей.

Все-же для исключения обычных ошибок ввода служат
специальные DB-компоненты, например для дат —
TDBDateTimeEditEh из библиотеки компонентов EhLIb,
или TDateEdit из библиотеки RxLib.
Или вводят данные в обычных компонентах TDateTimePicker
а после проверки введенных данных уже вручную вставляют
их в базу.

Тоже самое и с другими данными — целыми и дробными числами,
списками возможных значений и пр.

Самое простое(но не самое правильное) — взять компонент
ApplicationEvents и обрабатывать любое событие OnException.

CODE
void __fastcall TForm1::ApplicationEvents1Exception(TObject *Sender,
Exception *E)
{
ShowMessage(«Случилась большая беда: «+E->Message);

}
//—————————————————————————

наверное более правильным будет вот так:

CODE
//—————————————————————————
// для некоего поля Area типа TDateTime
// используем обработчик OnSetText
//
void __fastcall TForm1::ClientDataSet1AreaSetText(TField *Sender,
const AnsiString Text)
{
try{
// здесь выполняем любые проверки значения поля
TDateTime dtDate = StrToDate(Text);
ClientDataSet1Area->AsDateTime = dtDate;
}catch(…){
ShowMessage(«Неверное значение в поле: ‘Area’ !»);
// Abort(); — Кажется он здесь не нужен.
}
}
//—————————————————————————

а задать предварительные ограничения на значения полей
можно в свойстве CustomConstraint проверяемого поля,
например: Area> 1000 and Area < 2850 (для целых чисел)
а в ConstraintErrorMessage — сообщение об ошибке, которое
будет при этом выводиться.

Можно прочитать также здесь:
http://dchumichkin.narod.ru/bookdatabase/glava_06.html

Лена

Отправлено: 04.10.2006, 17:14

Мастер участка

Группа: Участник
Сообщений: 501

Что-то в моем случае не удается сделать проверку.
В поле ввода дат ввела маску !00/00/0000;1;_
Реально там такие значения: 08.12.1999

Теперь осталось проверить допустимые значения. Объясните, пожалуйста, почему не срабатывает обработчик OnValidate ниже:

CODE
void __fastcall TDataModule2::ClientDataSetGrupstimeValidate(
TField *Sender)
{
Word Year, Month, Day;
DecodeDate(Sender->Value, Year, Month, Day);
if(Day > 31 || Day < 1 || Month > 12 || Month < 1)
{
ShowMessage(«Не верно»);
Abort();
}
}


Если поместить в OnSetText, то запись возвращается в исходное положение.

Код:

CODE
void __fastcall TForm1::ClientDataSet1AreaSetText(TField *Sender,
const AnsiString Text)
{
try{
// здесь выполняем любые проверки значения поля
TDateTime dtDate = StrToDate(Text);
ClientDataSet1Area->AsDateTime = dtDate;
}catch(…){
ShowMessage(«Неверное значение в поле: ‘Area’ !»);
// Abort(); — Кажется он здесь не нужен.
}
}


Генерирует промежуточное исключение самой IDE.
Как убрать все исключения и почему OnValidate вообще не работает?

Отредактировано Лена — 04.10.2006, 17:16

Admin

Отправлено: 04.10.2006, 17:43

Владимир

Группа: Администратор
Сообщений: 1190

QUOTE
Если поместить в OnSetText, то запись возвращается в исходное положение.

А приведите код ? Где вы в OnSetText делаете проверку
на допустимость значений.

(в приведенном примере эта проверка выполняется
в блоке try…catch и в случае ошибки — генерится
исключение и выдается сообщение об ошибке.
В этот же try можете засунуть и другие проверки
на возможные значения и в случае ошибки генерить
исключение например throw 1, которое будет
обрабатываться в блоке catch)

CODE
//—————————————————————————
// для некоего поля Area типа TDateTime
// используем обработчик OnSetText
//
void __fastcall TForm1::ClientDataSet1AreaSetText(TField *Sender,
    const AnsiString Text)
{
 try{
     // здесь выполняем любые проверки значения поля
      TDateTime dtDate = StrToDate(Text); // проверка на формат даты
      if(dtDate < StrToDate(«12.10.2003»)) throw 1; // дата меньше указанной — ошибка
      ClientDataSet1Area->AsDateTime = dtDate; // всё нормально
    }catch(…){
        ShowMessage(«Неверное значение в поле: ‘Area’ !»);
                   }
}
//—————————————————————————


Лена

Отправлено: 04.10.2006, 18:08

Мастер участка

Группа: Участник
Сообщений: 501

>А приведите код ? Где вы в OnSetText делаете проверку

На «ты» smile.gif

Я там вписываю то же что и в OnValidate:

CODE
Word Year, Month, Day;
DecodeDate(Sender->Value, Year, Month, Day);
if(Day > 31 || Day < 1 || Month > 12 || Month < 1)
{
ShowMessage(«Не верно»);
Abort();
}

Что касается кода:

CODE
void __fastcall TForm1::ClientDataSet1AreaSetText(TField *Sender,
const AnsiString Text)
{
try{
// здесь выполняем любые проверки значения поля
TDateTime dtDate = StrToDate(Text); // проверка на формат даты
if(dtDate < StrToDate(«12.10.2003»)) throw 1; // дата меньше указанной — ошибка
ClientDataSet1Area->AsDateTime = dtDate; // всё нормально
}catch(…){
ShowMessage(«Неверное значение в поле: ‘Area’ !»);
}
}


то допустим я ввела ошибочно дату 08.14.1988. Поскольку месяца 14 не бывает, то на строке TDateTime dtDate = StrToDate(Text); IDE генерит сразу исключение. Хочется избавиться от исключения которое генерит IDE.

Отредактировано Лена — 04.10.2006, 18:10

Admin

Отправлено: 04.10.2006, 18:18

Владимир

Группа: Администратор
Сообщений: 1190

Так а зачем от него избавляться-то ?
Ведь тогда сразу это исключение перехватит catch,
в котором и можно предупредить о неправильном
вводе в конкретном поле.

CODE
    catch(…){
        AnsiString s = «Неправильная дата в поле ‘Дата’: «+Text;
        ShowMessage(s);
                  }

И никаких других окошек/исключений не будет.

Admin

Отправлено: 04.10.2006, 18:26

Владимир

Группа: Администратор
Сообщений: 1190

Sender->Value в OnSetText работать не должно.
Значение полю там еще не присвоено, оно только в Text !

Если значение правильно — его необходимо там присвоить
ClientDataSet1Area->AsDateTime = dtDate;
или для текстового поля скажем
ClientDataSet1Area->AsString = Text;

Лена

Отправлено: 04.10.2006, 18:36

Мастер участка

Группа: Участник
Сообщений: 501

Понятно. Оставлю IDE исключение. smile.gif
Просто мне удалось избавиться от исключения IDE когда требуется обязательный ввод значений. Я реализовала так:

CODE
void __fastcall TDataModule2::ClientDataSetOrganBeforePost(
TDataSet *DataSet)
{
if(Form1->DBGrid3->Fields[1]->Value.IsNull() || Form1->DBGrid3->Fields[3]->Value.IsNull())

{
ShowMessage(«Поля «Фамилия» и «Имя» должны быть заполнены»);
Abort();
}
}

Пока пользователь не введет значения будет при переходе на новую строку получать ShowMessage.

Отредактировано Лена — 04.10.2006, 18:38

Admin

Отправлено: 04.10.2006, 18:45

Владимир

Группа: Администратор
Сообщений: 1190

«Понятно. Оставлю IDE исключение»

Что за IDE исключение ???
В случае с OnSetText будет показываться окошко только с тем
текстом, что будет в ShowMessage() в catch.

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

Лена

Отправлено: 04.10.2006, 18:49

Мастер участка

Группа: Участник
Сообщений: 501

Вот то единственное исключение которое происходит до сработки catch. Оно на строке:
TDateTime dtDate = StrToDate(Text);

P.S. Да без среды IDE все нормально — исключения нет. Просто думала избавиться от него и в период разработки. smile.gif

Отредактировано Лена — 04.10.2006, 18:51

Присоединить изображение

Присоединить изображение

Admin

Отправлено: 04.10.2006, 18:51

Владимир

Группа: Администратор
Сообщений: 1190

Так вот об этом я и пишу, что запустив программу не из
среды C++Builder этого исключения не будет !
Только сообщение ShowMessage из catch
Admin

Отправлено: 04.10.2006, 18:55

Владимир

Группа: Администратор
Сообщений: 1190

А в период разработки тоже избавиться не сложно — это
галочка в опциях проекта, не помню сейчас где,
и эти исключения тоже не будут появляться из среды разработки.
Лена

Отправлено: 04.10.2006, 19:00

Мастер участка

Группа: Участник
Сообщений: 501

Ясно.

P/S/
Для общего развития как можно использовать onValidate событие?
Оно у меня вообще не отробытывает:

CODE
void __fastcall TDataModule2::ClientDataSetGrupstimeValidate(
     TField *Sender)
{
int c = 0; //поставила точку остановки и не поподаю сюда
}


Не могу попасть в тело события.

Admin

Отправлено: 04.10.2006, 19:44

Владимир

Группа: Администратор
Сообщений: 1190

Если я правильно понял: (этот документ уже советовал изучить)
http://dchumichkin.narod.ru/bookdatabase/glava_06.html

то событие OnValidate происходит уже после события OnSetText.

То есть последовательность событий следующая:
1. Начало редактирования — перевод в состояние dsEdit (dsInsert)
2. OnSetText
3. попытка присвоения введенного значения полю
4. OnValidate
5. OnChange
6. Post() данных в базу.

Оба события наступают до Post(), но отличаются тем, что в событии
OnSetText значение полю еще не присвоено
, а в OnValidate — уже
присвоено
 — и в OnValidate можно его проверить и или пропустить
дальше, или отменить изменения — через Abort().

То есть — поскольку значение даты было в корне неверно,
то происходила попытка присвоения этого неправильного
значения полю(пункт 3.) и генерилось исключения, то есть до события
OnValidate дело просто не доходило.

Попробуйте ввести допустимое значения (с точки зрения формата
данных) в это поле и в onValidate событие наступит.

В нем можно будет проверить, например допустимый диапазон дат,
и если что-то не так — отменить ввод (событие Post) через Abort().

CODE
//—————————————————————————

void __fastcall TForm1::ClientDataSetLAST_NAMEValidate(TField *Sender)
{
if(ClientDataSetLAST_NAME->AsString == «Лена»){
ShowMessage(«Имя Лена в данном поле недопустимо !»);
Abort();
}
}
//—————————————————————————


Лена

Отправлено: 04.10.2006, 21:23

Мастер участка

Группа: Участник
Сообщений: 501

Огромное спасибо! Теперь все понятно!

>
Обработка исключительных ситуаций
, обработка ошибок

  • Подписаться на тему
  • Сообщить другу
  • Скачать/распечатать тему



Сообщ.
#1

,
08.08.07, 12:09

    Junior

    *

    Рейтинг (т): нет

    Прочитал много литературы по обработке исключительных ситуаций, но не могу понят ь до конца как использовать все это?
    Обьясните или напишите пример кода, когда например есть

    ExpandedWrap disabled

      int i=0;

      i=i/i;

    вызывается исключение EDivByZero
    Как его обработать программно, например вывести окно с сообщением …


    sten_11



    Сообщ.
    #2

    ,
    08.08.07, 12:25

      Senior Member

      ****

      Рейтинг (т): 13

      ExpandedWrap disabled

        int i=0;

        int a=10;

        try { double b= a/i; }

        catch(…) {ShowMessage(«Не могу выполнить операцию»);}


      forward89



      Сообщ.
      #3

      ,
      08.08.07, 12:39

        Junior

        *

        Рейтинг (т): нет

        Цитата sten_11 @ 08.08.07, 12:25

        ExpandedWrap disabled

          int i=0;

          int a=10;

          try { double b= a/i; }

          catch(…) {ShowMessage(«Не могу выполнить операцию»);}

        оно ничего не меняет, там же используются классы и оператор throw, а этот код вызывает ошибку компилятора


        Seva



        Сообщ.
        #4

        ,
        08.08.07, 12:41

          Цитата forward89 @ 08.08.07, 12:39

          оно ничего не меняет, там же используются классы и оператор throw, а этот код вызывает ошибку компилятора

          Это ты о чём?


          GarF1eld



          Сообщ.
          #5

          ,
          08.08.07, 12:46

            ExpandedWrap disabled

              int i=0;

              int a=10;

              double b;

              try

              {

                  b = a/i;

              }

              catch(EDivideByZero &ex)

              {

                  //деление на 0

                  ShowMessage(ex.Message);

              }

              catсh(…)

              {

                 ShowMessage(«Неизвестная ошибка»);

              }

            Добавлено 08.08.07, 12:47
            если нужно произвести какую-либо опреацию по-любому, то заключи конструкцию try…catch в try..__finally


            Akme



            Сообщ.
            #6

            ,
            08.08.07, 12:48

              ExpandedWrap disabled

                try{

                    int i=0;

                    i=i/i;

                    /* другой код */

                }catch(EDivByZero &e) //ловим деление на 0

                {

                    ShowMessage(«Деление на ноль»);

                }catch(…) // ловим всё остальное

                {

                    ShowMessage(«незапланированная ошибка»);

                }

              Добавлено 08.08.07, 12:48
              GarF1eld опередил… =)


              sten_11



              Сообщ.
              #7

              ,
              08.08.07, 12:52

                Senior Member

                ****

                Рейтинг (т): 13

                Цитата

                оно ничего не меняет, там же используются классы и оператор throw, а этот код вызывает ошибку компилятора

                Разъясни ???? У меня поймал исключение, выкинул мессаг.


                forward89



                Сообщ.
                #8

                ,
                08.08.07, 14:07

                  Junior

                  *

                  Рейтинг (т): нет

                  Цитата

                  ExpandedWrap disabled

                    int i=0;

                    int a=10;

                    double b;

                    try

                    {

                        b = a/i;

                    }

                    catch(EDivideByZero &ex)

                    {

                        //деление на 0

                        ShowMessage(ex.Message);

                    }

                    catсh(…)

                    {

                       ShowMessage(«Неизвестная ошибка»);

                    }

                  ошибка компиляции:
                  [C++ Error] Unit1.cpp(34): E2303 Type name expected
                  [C++ Error] Unit1.cpp(34): E2377 Catch statement missing )
                  [C++ Error] Unit1.cpp(39): E2206 Illegal character ‘с’ (0xf1)
                  [C++ Warning] Unit1.cpp(43): W8004 ‘b’ is assigned a value that is never used
                  неизвестный идентификатор ex!

                  На счет оператора throw читал по линке http://www.programmersclub.ru/39, что в обработке ошибок используется throw

                  Добавлено 08.08.07, 14:16
                  ну там не

                  ExpandedWrap disabled

                    catch(EDivideByZero &ex)

                  а

                  ExpandedWrap disabled

                    catch(EDivByZero &ex)

                  тогда компилится, но ошибку не отлавлюет все равно, мессага от компилятора — обработка не срабатывает (


                  GarF1eld



                  Сообщ.
                  #9

                  ,
                  08.08.07, 14:52

                    код писал от руки, так что ошибки могли быть.
                    Теперь написал пример и все работает

                    ExpandedWrap disabled

                              int a = 10;

                              int b = 0;

                              try

                              {

                                      float c = a / b;

                              }

                              catch(EDivByZero &ex)

                              {

                                      MessageBox(NULL, ex.Message.c_str(), «Division by zero», MB_OK | MB_ICONERROR);

                              }

                    Добавлено 08.08.07, 14:53
                    + ты попробуй продолжить выполнение проги после ругания дебаггера. Вылезит твое окошко ;)

                    Добавлено 08.08.07, 14:55
                    Если хочешь отрубить ругань дебаггера, то сними флажок Integrated debugging в Debugging options (Tools->DebuggerOptions…)
                    ;)


                    forward89



                    Сообщ.
                    #10

                    ,
                    08.08.07, 15:36

                      Junior

                      *

                      Рейтинг (т): нет

                      ну да тогда все работает. Тогда если несколько усложнить задачу, скажем

                      ExpandedWrap disabled

                         try {

                                  fmMain->server->Open();

                             }

                         catch(…)

                             {

                                  ShowMessage(«Can’t create server»);

                             }

                      Вот в этой комплекции открывается порт сервера, при ошибке выводится сообщение о невозможности создания, а в случае если все прошло без ошибок надо вывести месагу о Успешном создании. Как это сделать, если поместить строчку ШоуМессадж(«Все ок») после этого кода, тогда при ошибке будет выводится оба сообщения- неверно. А как же тогда организовать такую шнягу? И кто что может сказать о throw?

                      Добавлено 08.08.07, 16:26
                      и как обрабатываюся ошибки в компонентах ТКлиентСокет и ТСерверСокет? Там есть события OnError, но оно както непонятно отлавливается? Использовать трай-кетч или эти события?


                      GarF1eld



                      Сообщ.
                      #11

                      ,
                      08.08.07, 16:53

                        Цитата forward89 @ 08.08.07, 15:36

                        Как это сделать

                        ExpandedWrap disabled

                           try {

                                    fmMain->server->Open();

                                    // если происходит ошибка, то управление сразу передается в блок catch т.е код после этих коментов при ошибке не выполняется

                                    ShowMessage(«Server created succesfully»);

                               }

                           catch(…)

                               {

                                    ShowMessage(«Can’t create server»);

                               }

                        Добавлено 08.08.07, 16:59
                        c помощью throw ты сам можешь выбивать исключения. Например, тебе нужно чтоб число, введенное в textBox было положительное

                        ExpandedWrap disabled

                          if (Edit1->Text.ToInt() < 1) throw EAbort(«Entered number is less than zero»); //генерирует исключение

                        Добавлено 08.08.07, 17:03
                        если ты хочешь распознавать свое исключение среди других, то можешь просто создать производный класс от базового EAbort….где-то так

                        ExpandedWrap disabled

                          class EMyException : public EAbort

                          {

                          public:

                                  EMyException(const AnsiString Msg): EAbort (Msg) {}

                          };

                          //…

                          throw EMyException(«message»);

                          //…

                          catch(EMyException &ex)

                          {

                          //…

                          }

                        Добавлено 08.08.07, 17:06

                        Цитата forward89 @ 08.08.07, 15:36

                        Использовать трай-кетч

                        Лучше используй try…catch


                        Seva



                        Сообщ.
                        #12

                        ,
                        09.08.07, 04:59

                          При делении на нуль в Билдере по умолчанию используются два исключения:
                          1. EDivByZero — для целочисленного деления
                          2. EZeroDivide — для вещественных чисел


                          Akme



                          Сообщ.
                          #13

                          ,
                          09.08.07, 05:39

                            ExpandedWrap disabled

                              class TMyExcept

                              {

                              };

                            ExpandedWrap disabled

                              // где-то в коде….

                              try{

                                  i=i/i;

                                  /* Много операций с РАЗНЫМИ числами */    

                                  if( что_то_меня_не_устраивает )

                                        throw TMyExcept();

                                  ShowMessage(«Они таки поделились!»);      

                              }

                              catch(EDivByZero &e) //ловим деление на 0

                              {

                                  ShowMessage(«Деление на ноль целых чисел»);

                              }

                              catch(EZeroDivide &e)

                              {

                                  ShowMessage(«Деление на ноль вещественных чисел»);

                              }

                              catch( TMyExcept &e )

                              {

                                  ShowMessage(«Я таки поймал свой эксепшн!!!»)

                              }

                              catch(…) // ловим всё остальное

                              {

                                  ShowMessage(«незапланированная ошибка»);

                              }

                            Неужели еще что-то непонятно?


                            Uhri



                            Сообщ.
                            #14

                            ,
                            09.08.07, 07:53

                              forward89, при использовании throw обрати внимание на конструкторы и деструкторы.

                              Если ты используешь throw в конструторе, то объект не будет создан в случае вызова исключения, например:

                              ExpandedWrap disabled

                                class MyClass

                                {

                                public:

                                  MyClass()

                                  {

                                     throw(EMyError());

                                  };

                                  class EMyError {};

                                };

                                //где-то в коде

                                MyClass * cls(NULL);

                                try

                                {

                                  cls = new MyClass;

                                }

                                catch(MyClass::EMyError)

                                {

                                  if(!cls)

                                    ShowMessage(«Ты увидишь это сообщение, т.е. объект не создан!»);

                                }

                              Если в деструкторе, то нужно быть внимательным, и вызывать исключение, после освобождения всей памяти, например:

                              ExpandedWrap disabled

                                class MyClass

                                {

                                int * pArr;

                                public:

                                  MyClass()

                                    : pArr(NULL)

                                  {

                                     pArr = new int [10];

                                  };

                                  ~MyClass()

                                  {

                                     throw(MyError());

                                     delete [] pArr;

                                     pArr = NULL;

                                  };

                                  class EMyError {};

                                };

                                //где-то в коде

                                MyClass * cls = new MyClass;

                                //… чего-то делаем

                                try

                                {

                                  delete cls;

                                }

                                catch(MyClass::EMyError)

                                {

                                  ShowMessage(«Исключение EMyError не позволит освободить память объекта pArr»);

                                }

                              Добавлено 09.08.07, 07:54
                              И вообще, почитай книгу какую, например Страуструпа, там всё разжевано.


                              forward89



                              Сообщ.
                              #15

                              ,
                              09.08.07, 11:58

                                Junior

                                *

                                Рейтинг (т): нет

                                Это все понятно, спасибо огромное. но терь конкретная проблема:

                                ExpandedWrap disabled

                                  void TChat::ConnectToServer(AnsiString HOST_)

                                  {

                                     // функция подключения к серверу

                                     fmMain->client->Host = HOST_;

                                     try {

                                            fmMain->client->Open();

                                            fmMain->txt_Chat->Lines->Add(«Подключенок к серверу:»+HOST_);

                                         }

                                     catch(…)

                                         {

                                          ShowMessage(«Сервер не отвечает»);

                                         }

                                  }

                                где client — это обьект типа TClientSocket. И вот при попытке подключения ошибочного подключения выполняется строчка

                                ExpandedWrap disabled

                                  fmMain->txt_Chat->Lines->Add(«Подключенок к серверу:»+HOST_);

                                и выводитя месага от компилятора «Asynchronus socket error 10049». Исключение не перехватывается!!! Почему?

                                0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)

                                0 пользователей:

                                • Предыдущая тема
                                • Borland C++ Builder/Turbo C++ Explorer
                                • Следующая тема

                                [ Script execution time: 0,0556 ]   [ 16 queries used ]   [ Generated: 8.06.23, 20:14 GMT ]  

                                Возможно, вам также будет интересно:

                              • C 0204 ошибка konica minolta
                              • Bx shellext gettempfilename failed ошибка
                              • Bwsb 51051 стиральная машина коды ошибок
                              • Bwe ошибка на скании что это значит
                              • Bwclient dll world of warplanes ошибка

                              • Понравилась статья? Поделить с друзьями:
                                0 0 голоса
                                Рейтинг статьи
                                Подписаться
                                Уведомить о
                                guest

                                0 комментариев
                                Старые
                                Новые Популярные
                                Межтекстовые Отзывы
                                Посмотреть все комментарии