Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

OOP / Лекция 7

.pdf
Скачиваний:
23
Добавлен:
20.04.2015
Размер:
141.85 Кб
Скачать

Хотя, как видите, деструктор Hold и не вызывается, деструктор его полностью конструированного элемента iStr вызывается правильно и память освобождается.

12 .Динамические объекты

Если объект создается с помощью операции new своего класса, и в конструкторе класса генерируется исключение, то деструктор класса не вызывается. В этом отношении все происходит совершенно так же, как описано выше для явных вызовов конструктора (т. е. для локальных объектов).

Хотя деструктор не вызывается, память объекта (не та, на которую он может ссылаться посредством указателей, а его собственная) автоматически удаляется. По сути, то же происходит и с локальными объектами, только там не полностью конструированный объект просто удаляется со стека, здесь же вызывается операция класса delete. Вот пример:

Листинг 32. Исключение в конструкторе динамического объекта

/////////////////////////////////

// Dynamic.срр: Исключение при операции класса new.

//

#include <iostream.h> #include <string.h> #pragma hdrstop #include <condefs.h> const int MaxLen = 80; class AClass {

char msg[MaxLen]; public:

AClass () // Конструктор, выбрасывающий исключение.

{ {

cout << "AClass: constructor." << endl; cout << "Throwing exception..." << endl; throw "Exception!";

}

~AClass() // Деструктор.

{

cout << "AClass: destructor."<< endl; }

void *operator new (size t size) // new класса.

{

cout<< "AClass: new." << endl; return ::new char[size];

}

void operator delete(void *p) // delete класса.

{

cout << "AClass: delete." << endl; ::delete[] p;

}

};

int main() { AClass *ap;

try {

ар = new AClassO; // Попытка выделить, объект.

}

catch(char *str) {

cout << "Caught a sring: " << str << endl;

)

return 0;

}

Эта программа выводит: AClass: new.

AClass: constructor. Throwing exception...

AClass: delete.

Caught a string: Exception!

Таким образом, при исключении память объекта освобождается операцией класса delete.

13. Классы исключений

Часто для обработки исключительных ситуаций используются классы, специально предназначенные для этой цели. Главное в управлении исключениями — отыскать нужный обработчик, а это делается путем сопоставления типа выброшенного объекта с типами, объявленными в обработчиках. Поэтому иногда для исключений определяют совершенно “пустые” классы, однако с уникальными именами.

Классы исключений программы могут быть организованы в иерархическую структуру. Схожие типы исключений объявляются в качестве производных одного и того же базового класса, являющегося их обобщением. Используя полиморфные механизмы, можно перехватывать только указатель или ссылку на базовый класс; полиморфизм обеспечит адекватную обработку исключения любого производного класса. Вот примерная схема:

class GenericFault { // Обобщенная ошибка. public: virtual void Report ();

//

// Конкретные типы ошибок...

//

class OpenError: public GenericFault { public:

void Report();

}

class BadHeader: public GenericFault { public: void Report ();

class BadRecord: public GenericFault ( public: void Report () ;

}

int main() { try {

}

catch(GenericFault &err) { err.Report () ;

}

return 0;

}

14.Предопределенные исключения

Вбиблиотеке C++ имеется несколько предопределенных классов исключений.

15 xmsg

Класс xmsg предназначен для передачи строковых сообщений об исключениях. Он объявлен в заголовке except, h:

class EXPCLASS xmsg : public std::exception { public:

xmsg(const std::string &msg); xmsg(const xmsg &);

virtual ~xmsg() throw ();

xmsg & operator=(const xmsg &) ;

virtual const char * what() const throw (); const std::string & why() const;

void raise () throw(xmsg); private:

std::string *str; };

Применять класс xmsg очень просто: #include <iostream.h>

#include <except.h> #pragma hdrstop #include <condefs.h> int main() {

try {

xmsg X("Exception!"); throw X;

// или

//

X.raise () ;

}

catch(xmsg Smsg) {

cout << "Caught in main: " << msg.why() << end1;

}

return 0;

}

В классе имеется функция-элемент raise (), посредством которой объект выбрасывает сам себя. Ею можно воспользоваться вместо оператора throw. Функция why () возвращает стандартную строку с сообщением, записанным в объект.

Класс xmsg считается устаревшим. Теперь в стандартной библиотеке C++ определяется ряд классов (производных от exception, как и xmsg), организованных иерархически. По сути они ничем друг от друга не отличаются; данные им имена ничего особенного не значат. Вот эти классы: class logic_error public exception class domain_error public logic_error class invalid argument public logic_error class

length_error public logic_error class out_of_range public logic_error class runtime error public exception class range error public runtime error class overflow_error public runtime error class underflow error public runtime error

Logic_error и runtime_error — производные от exception, а все остальные — от первых двух. Эти классы имеют конструктор, принимающий ссылку на стандартную строку, виртуальный деструктор и виртуальную функцию-элемент what (), которая возвращает указатель на константную строку С. Вот пример:

#include <iostream> #include <stdexcept> using namespace std;

static void f() ( throw runtime_error("a runtime error");

}

int main ()

{

try

{ f();

}

catch (const exceptions e) {

cout << "Got an exception: " << e.what() << endl; } return 0;

}

Программа печатает:

Got an exception: a runtime error

Иерархия и полиморфизм этих классов делают их весьма гибким средством организации обработки ошибок.

16. bad_alloc

Если операция new не может выделить запрашиваемую память, она выбрасывает исключение bad_alloc. Этот класс также является производным от exception:

class bad alloc : public exception { public:

bad_alloc () throw() : exception () { ; } bad_alloc(const bad_alioc&) throw()

{ ; }

bad_alloc& operator=(const bad_alloc&) throw() { return *this; }

virtual ~bad_alloc () throw ();

virtual const char * what () const throw()

{

return _RWSTD::_rw_stdexcept_BadAilocException; } };

Продемонстрировать реальную работу этого класса с реальной операцией new вряд ли возможно, да и не стоит. Можно, однако, выбросить bad_alloc вручную:

int main () { try {

throw bad_alloc();

} catch(const exception &e) (

cout << "Caught something: "<< e.what() “ endl;

}

return 0;

}

Функция what () объекта bad_alloc возвращает строку "bad alloc exception thrown".

В прежних версиях языка new при ошибке выбрасывала xalloc, класс, производный от xmsg:

class _EXPCLASS xalloc : public xmsg

{

public:

xalloc(const std::string &msg, _SIZE_T size); _SIZE_T requested () const.;

void raise () throw(xalloc); private:

_SIZE_T siz; };

Теперь этим классом пользоваться нельзя, и он остался в библиотеке C++Builder только для обеспечения совместимости со старыми библиотеками. Еще раньше операция new при отказе просто возвращала NULL. Такое поведение операции восстановить очень просто, вызвав функцию set_new_handler():

#include <new.h> set new handler (0);

Прототип set_new_handler () имеет вид typedef void (*new_handler)();

new_handler set__new_handler(new_handler rny_handler);

Функция предназначена для установки пользовательского обработчика ошибок глобальных операций new или new [ ]. Обработчик my handler может:

освободить память (удалить какой-то мусор) и возвратить управление;

вызвать функцию abort () или exit ();

выбросить исключение bad_alloc или производного типа.

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

17.Информация об исключении

Имеются три глобальные переменные, в которых хранится информация о текущем исключении (они объявлены в заголовке except.h):

_throwExceptionName содержит указатель на строку с именем типа исключения;

_throwFileNane содержит указатель на строку с именем файла, где произошло исключение;

_throwLineNumber — целое без знака, представляющее номер строки файла, где было выброшено исключение.

//////////////////////////////////////

// Loclnfo.cpp: Информация о точке выброса исключения.

//

#include <iostream.h> #include <stdexcept>

#pragma hdrstop #include <condefs.h> void f() {

throw invalid_argument("Exception from f(): ");

}

int main() { try { f () ;

}

catch(const exception &e) { cout << e.what()

<<_throwExceptionName << end1

<<" in file " << _throwFileName << end1

<<" line " << _throwLineNumber << end1;

}

return 0; } Программа печатает:

Exception from f(): invalid argument

in file C:\Projects\Chl2\LocInfo\LocInfo.cpp line 8

Соседние файлы в папке OOP