Главная » Исключения в Borland С++ Builder 6.0
В статье рассматриваются проблемы, возникающие при работе с исключениями в среде Borland C++ Builder 6.0 
Я не спроста уточнил, что все нижеизложенное относится в первую очередь к шестой версии среды, поскольку я натолкнулся на эти проблемы именно в ней, и не проверял прочие версии.
Итак, краткий инструктаж по применению исключений, согласно книгам, статьям и официальным исходникам.
Конструкция исключений имеет следующий вид.
Пример №1try // try - указывает на то, что дальше пойдет блок исключений
{
throw 1; // throw – ключевое слово, собственно и создающее исключение
}
catch(int a) // catch – указывает на то, что дальше пойдет блок отлова исключений
{
MessageDlg("Exception - 1",mtError, TMsgDlgButtons() << mbOK, 0); // Сообщение о // поимке исключения
};Теперь, разберем эту конструкцию поподробнее.
try
Ключевое слово, указывающее на начало блока исключений. Используется только в С++, а в С придется использовать __try. Однако, __try можно так же использовать в C++.
Блок исключений заключается в фигурные скобки, как это показано выше, и при необходимости, в нем создается исключение.
throw
Ключевое слово, создающее исключение. Иными словами, при создании исключения, throw инициализирует временный объект того типа, с помощью которого мы хотим создать исключение. В приведенном примере, мы используем тип int, соответственно, создается временный объект типа int, содержащий данные – 1.
catch
Ключевое слово, указывающее на начало блока обработки исключений. Здесь мы можем разместить любые реакции на пойманные исключения. В параметрах блока мы должны указать тип данных, использованный при создании исключений. Поскольку в приведенном выше примере мы создавали исключений типа int, то и слушать нам надо на предмет типа int. Так что мы указываем этот тип в скобках.
И вроде бы все! Создаем новый проект, помещаем на форму кнопочку, и вставляем в обработчик нажатия этой кнопки наш пример. Потом запускаем. Компилятор уверенно считывает строчки. Линкер не видит ничего подозрительного. Программа запускается, и радостно ожидает начала работы. Мы нажимаем на кнопочку…
Бах!!!
И хорошо, если вам скажут, что «Project XXX.exe raised exception class int with message 'Exception Object Address: 0x8E4C6E'. process stopped. use Step or Run to Continue.»
В некоторых случаях вас вообще могут вышвырнуть из среды, включая полное зависание всей Windows.
Итак, что же неправильно в этом коде?
Во-первых, давайте разберемся, что такое «Project XXX.exe raised exception…»
Это сообщение появляется тогда, когда программа, над которой трудится дебаггер, создает исключение. Проблема в том, что С++ Builder (равно как и Delphi) почему-то все исключения, которые находит, по умолчанию скидывает на стандартный обработчик.
Однако, подобное сообщение мы можем увидеть не только при обработке своего исключения. Это сообщение возникает так же в случаях, если это Operating System Exception (Исключение операционной Системы) или Language Exception (Исключение Языка).
В данном примере, мы работаем с помощью средств языка, нисколько не трогая (ну разве что самую малость) операционную систему.
Так что стоит сходить в гости к дебаггеру, и проверить – чем он там занимается.
Найти его можно по адресу: Tools->Debugger Options
Здесь нас интересует вкладка Language Exceptions. Заходим внутрь, и что мы видим? Налицо суровое нарушение правил безопасности! Оказывается, дебаггер успешно игнорирует исключения, принадлежащие Delphi, Microsoft, VisiBroker, CORBA! Но зачем? Ответ очевиден – каждый из этих шедевров мысли имеет свои собственные обработчики исключений, которые заточены под специфические нужды. И они вовсе не собираются пользоваться стандартным обработчиком.
Мы, конечно, можем вписать сюда тип int, но в этом случае дебаггер будет игнорировать все, что связано с этим типом данных. Это не есть правильно.
Раз сильные мира сего регистрируют тут свои типы данных, для корректной обработки, значит, мы просто обязаны создать свой тип данных, отвечающий за исключения.
Назовем его TCustomException. Кликаем по Add, и вписываем это в строчку диалога. Потом щелкаем OK. Все, поздравляю дамы и господа! Мы успешно зарегистрировали тип данных. То есть теперь дебаггер не будет обижаться на то, что мы используем для генерации исключений что-то, о чем он не знает.
Итак, уходим из опций дебаггера, и возвращаемся в программу.
Изменим код.
Пример №2сlass TCustomException{}; // Наш тип данныхTCustomException NewEx; // Объект класса (типа) TCustomExceptiontry // Начало блока создания исключений
{
throw NewEx; //Создание исключения
}
catch(TCustomException) // Начало блока отлова исключений
{
MessageDlg("Exception!!!",mtError, TMsgDlgButtons() << mbOK, 0); //Сообщение
}; Поскольку классы являются типами данных, мы без труда создаем свой TCustomException. Однако, неудобно создавать под каждое новое исключение – новый класс. Так что лучше создать объект класса TCustomException, что мы и делаем. Создаем объект NewEx, и используем его для создания исключения, которое потом с успехом отлавливается. В остальном конструкция работает так же, как вышеописанная, с той разницей, что она работает!
Однако, подобная конструкция тоже имеет проблемы. В случае более-менее сложной ситуации, нам придется выстраивать целые иерархии исключений. Чтобы этого не допускать, лучше пользоваться исключениями с параметрами.
Пример №3
//Класс для исключений с параметрами.
//Не забывать регистрировать его в опциях дебаггера!
class TEx
{
public:
int fCode;
TEx(int eCode){fCode=eCode;};
};// Код, встроенный в клавишу Button1
try
{
throw TEx(1301);
}
catch(TEx Ex)
{
if(Ex.fCode==1301){
MessageDlg("Exception!", mtError, mbOKCancel, 0);
};
} Иными словами, можно внутри рабочего алгоритма создавать исключения в любой непонравившейся вам ситуации, а затем в обработчике исключений, решать – что делать в каждом конкретном случае. Просто, удобно и надежно. Какие милые люди работают в Borland!
Надеюсь, эта статья поможет интересующимся в их неравном бою с замечательным (да, я на самом деле так считаю!) инструментом – Borland C++ Builder 6.0 Категория: Языки программирования | Просмотров: 184