Студопедия КАТЕГОРИИ: АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Примеры генерации и обработки исключительных ситуаций
Обработка простых ИС. В качестве операнда оператора throw можно использовать выражение любого базового или производного типа. Для проверки этого утверждения я написал программу с таким фрагментом кода: double Vec[5]={5,4,3,2,1}; int SomeValue; do { cin>>SomeValue; try { if(SomeValue<0) throw 10; f=0.5; if(SomeValue>0) throw f; if(SomeValue==0) throw Vec; } catch(int ex_k) { cout<<ex_k<<endl; // выводит 10 } catch(float ex_f) { cout<<ex_f<<endl; // выводит 0.5 } catch(double ex_Vec[5]) { cout<<ex_Vec[0]<<endl; // выводит 5 } }while(1);
Удивительно, но программа работает так, как и предполагалось. Собственные классы ИС. Механизм обработки ИС в языке С++ позволяет создавать и использовать свои собственные классы ИС, благодаря чему открываются дополнительные возможности обработки ИС и управления ходом вычислений, которые могут быть реализованы в методах класса. Вот простой пример определения и использования собственного класса ИС. class CMyExc { protected: CString m_sMsg; public: CMyExc(char * Msg) { m_sMsg=Msg;} ~CMyExc() {} char * GetErrorMsg(){ return m_sMsg.GetBuffer(m_sMsg.GetLength());} };
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]) { // … BOOL Cond; // … try { if(!Cond) { CMyExc exc("Terrible error!"); throw exc; } } catch(CMyExc ex) { cout<<ex.GetErrorMsg()<<endl; } return 1; }
Естественно, что в реальной программе класс CMyExc будет иметь более содержательную функциональность.
Исключительные ситуации и освобождение памяти. При генерации ИС в некоторой функции выполнение этой функции прекращается непосредственно на операторе throw. При этом для объектов, созданных в функции (в этом случае часто говорят «созданных на стеке»), вызываются их деструкторы, которые и освобождают память и выполняют другие предусмотренные действия по корректному разрушению объекта. Вместе с тем, память, выделенная с помощью операции new, автоматически не освобождается и ее должен освободить программист явным образом перед генерацией ИС. Например, пусть имеется такая функция: void MyFunction() { CSomeClass Obj; float *Arr=new float [10]; double *BigBuf=new double [10000]; if(!BigBuf) throw "Покупайте память!"; // ... delete [] Arr; delete [] BigBuf; }
Если память для BigBuf выделена не будет, то будет сгенерирована ИС, выполнение функции прекратится и два последних оператора функции не будут выполнены, вследствие чего выделенная для указателя Arr память не будет освобождена. Вместе с тем, деструктор для Obj будет вызван, объект будет корректно разрушен и занятые им ресурсы полностью освобождены. Где же выход? Во-первых, можно переписать функцию в таком виде: void MyFunction() { CSomeClass obj; float *Arr=new float [10]; double *BigBuf=new double [10000]; if(!BigBuf) { delete [] Arr; throw "Покупайте память!"; } // ... delete [] Arr; delete [] BigBuf; }
Во-вторых, выделение памяти для указателей можно вынести в класс или использовать так называемые интеллектуальные указатели. 16.5. Классы исключительных ситуаций Visual C++ и примеры их использования Библиотека классов MFC включает иерархию классов, предназначенных для обработки ИС. В основе иерархии находится базовый класс CException и 11 производных от него классов. Вы можете конструировать свой собственный класс ИС как производный от любого из них. Родительским классом для CException является CObject.
Класс CException можно использовать для перехвата всех ИС, хотя это и не лучшая идея. У него есть конструктор и деструктор, которые в данном случае мы обсуждать не будем, и методы: virtual BOOL GetErrorMessage( LPTSTR lpszError, UINT nMaxError, PUINT pnHelpContext = NULL ); virtual int ReportError( UINT nType = MB_OK, UINT nMessageID = 0 ); void Delete( );
Метод GetErrorMessage() позволяет получить текст сообщения об ошибке, а метод ReportError() можно использовать непосредственно для вывода сообщения об ошибке. Метод необходимо использовать для освобождения памяти, выделенной для экземпляра объекта указателя на класс CException. Пример использования GetErrorMessage() и Delete(): try { CFile file("abc.txt",CFile::modeRead); // обрабатываем файл } catch(CException *ex) { char Mes[1000]; ex->GetErrorMessage(Mes,sizeof(Mes)); cout<<Mes<<endl; ex->Delete(); }
Если файл с именем "abc.txt" не существует, то будет выведено сообщение «Файл "abc.txt" не найден». Если метод Delete() вызван не будет, то и память, выделенная для объекта ex, не будет освобождена. В следующем фрагменте программы иллюстрируется функция ReportError(): try { CFile file("abc",CFile::modeRead); } catch(CException *ex) { ex->ReportError(); ex->Delete(); }
В этом случае будет выведено окно сообщения об ошибке с тем же текстом «Файл "abc.txt" не найден». Приведенные примеры использования класса CException являются чисто иллюстративными, так как для обработки ИС, вызванных файловыми операциями, лучше использовать класс CFileException.
Обработка ИС, ориентированная на компиляторы от Microsoft В программах, разрабатываемых для компиляторов Microsoft, можно использовать блоки обработки ИС try-except и try-finally. Поясним их на примере из MSDN:
#include <excpt.h> #include <stdlib.h> int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) { puts("in filter."); if (code == EXCEPTION_ACCESS_VIOLATION) { puts("caught AV as expected."); return EXCEPTION_EXECUTE_HANDLER; } else { puts("didn't catch AV, unexpected."); return EXCEPTION_CONTINUE_SEARCH; }; } Void MSSpecExc() { int* p = 0x00000000; // pointer to NULL puts("hello"); __try{ puts("in try"); __try{ puts("in try"); *p = 13; // causes an access violation exception; }__finally{ puts("in finally. termination: "); puts(AbnormalTermination() ? "\tabnormal" : "\tnormal"); } }__except(filter(GetExceptionCode(), GetExceptionInformation())){ puts("in except"); } puts("world"); } Вывод программы будет таким (комментарии справа добавлены):
hello in try // ИС во внешнем try-блоке in try // ИС во вложенном try-блоке in filter // выполняется фильтр; возвращается 1 in finally // разворачивание вложенного блока finally in except // передача управления выбранному обработчику world // выполнение кода вне обработчиков ИС
Главной особенностью блока try-finally является то, что программный код, помещенный после finally, выполняется как при наступлении ИС, так и в случае ее отсутствия, что позволяет, например, освобождать в нем такие ресурсы, которые должны быть освобождены всегда.
Классы Пример класса TVector
Этот пример реализован в проекте Vector (консольное приложение с поддержкой MFC). Содержимое заголовочного файла TVector.h (директивы препроцессора и компилятора опущены): Содержимое файла реализации TVector.cpp (директивы препроцессора и компилятора опущены):
Тестирование класса:
|
|||||||||||||||||||||||||||
Последнее изменение этой страницы: 2018-04-12; просмотров: 437. stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда... |