Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lutsik_Yu_A_Obektno_orientir_programmir_na_yaz.pdf
Скачиваний:
63
Добавлен:
11.05.2015
Размер:
4.33 Mб
Скачать

}

}

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

void f() { A obj;

 

. . .

}

throw new A;

Р

При этом необходимо решить вопрос о необходимости удаления динамически

созданного объекта исключения (например в блоке catch). В противном случае возможны утечки памяти.

ключительную ситуацию сначала на более низком уровнеГвложенностиУ блока try, а затем передать ее на более высокий уровень для продолжения обработки. Для того чтобы сделать это, нужно использовать throw без аргументов. В этом

8.2. Перенаправление исключительных ситуаций

 

Иногда возникает положение, при котором необходимо обработатьИ

ис-

случае исключительная ситуация будет перен правленаБк следующему подхо- дящему обработчику (подходящий обработч не ищется ниже в текущем спи-

ске − сразу осуществляется поиск на более высо ом уровне). Приводимый ниже

пример демонстрирует организацию такой п ред чи. Программа содержит вло-

 

 

 

 

 

 

 

 

 

а

женный блок try и соответствующий блок catch. Сначала происходит первичная

 

 

 

 

 

 

 

 

ик

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

уровень для дальнейшей обрабо ки.

е

 

#include<iostream>

 

т

 

 

using namespace std;

 

 

 

 

 

 

 

 

 

 

 

void func(int i)

 

о

 

 

 

{ try{

 

 

и

 

 

 

 

 

 

 

 

 

 

 

 

 

if(i) throw "Error";

 

 

 

 

}

 

 

л

 

 

 

 

 

 

 

 

 

 

 

 

 

catch(char *s) {

 

 

 

 

 

 

 

 

б

выполняется первый обработчик"<<endl;

 

cout<<s<<"-

 

throw;

 

 

 

 

 

 

 

}

и

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

int main() { try{

func(1);

}

catch(char *s) {

174

cout<<s<<"- выполняется второй обработчик"<<endl;

}

}

Результат выполнения программы: Error - выполняется первый обработчик Error - выполняется второй обработчик

Если ключевое слово trow используется вне блока catch, то автоматически будет вызвана функция terminate(), которая по умолчанию завершает програм-

му.

Р

 

И

 

8.3. Исключительная ситуация, генерируемая оператором new

 

Следует отметить, что некоторые компиляторы поддерживают генерацию

исключений в случае ошибки выделения памяти посредством оператора new, в частности исключения типа bad_alloc. Оно может быть перехвачено и необхо-

димым образом обработано. Ниже в программе рассмотрен пример генерации и

обработки исключительной ситуаций bad alloc. УИскусственно вызывается

ошибка выделения памяти и перехватывается исключительная ситуация.

 

#include <new>

 

 

 

 

Г

 

 

 

 

 

Б

 

#include <iostream>

 

 

 

 

using namespace std;

 

 

а

 

int main()

 

 

 

 

 

{

double *p;

 

 

 

к

 

 

 

try{

 

 

 

е

 

 

 

 

 

 

 

 

 

 

 

 

 

}

while(1) p=new double[100]; // генерация ошибки выделения памяти

 

 

 

 

 

 

 

 

 

 

 

 

catch(bad alloc exept) {

 

 

// обработчик xalloc

 

 

 

 

 

 

т

 

 

 

 

 

 

cout<<"В зникло исключение"<<exept.what()<<endl;

 

 

}

 

 

о

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

return 0;

 

 

 

 

 

 

 

}

 

 

и

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

В случае если компилятором не генерируется исключение bad_alloc, то

можно это исключение создать искусственно:

 

б

 

 

 

 

 

 

 

 

#include <new>

 

 

 

 

 

и

 

 

 

 

 

 

 

 

Б

#include <iostream>

 

 

 

 

using namespace std;

 

 

 

 

int main()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

{

double *p;

 

 

 

 

 

 

 

 

bad_alloc exept;

 

 

 

 

 

 

 

try{

 

 

 

 

 

 

 

 

 

 

if(!(p=new double[100000000])) // память не выделена p==NULL

 

 

 

throw exept;

 

 

// генерация ошибки выделения памяти

 

 

 

 

 

 

 

 

 

 

175

}

 

catch(bad_alloc exept) {

// обработчик bad_alloc

cout<<"Возникло исключение "<<exept.what()<<endl;

}

 

return 0;

 

}

 

Результатом работы программы будет сообщение:

Возникло исключение bad

allocation

 

Р

Оператор new появился в языке C++ еще до того, как был введен меха-

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

ется, чтобы new работал именно так, надо вызвать функцию set_new handler() с

параметром 0. Кроме того, с помощью set_new_handler() можно задать функ-

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

set_new_handler (в заголовочном файле new) принимает в качестве аргумента

указатель на функцию, которая не принимает никаких аргументов и возвращает

void.

 

 

 

 

 

 

 

 

 

 

У

 

 

 

 

 

 

 

 

 

Г

#include<new>

 

 

 

 

 

 

 

 

 

 

 

 

Б

 

#include<iostream>

 

 

 

 

 

 

using namespace std;

 

 

 

 

 

 

 

 

 

 

а

 

void newhandler( )

 

 

 

 

 

{

cout << "The new_handler is called: ";

 

 

throw bad_alloc( );

 

 

 

к

 

 

 

 

 

е

 

 

 

}

return;

 

 

 

 

 

 

 

 

 

 

 

 

 

т

 

 

 

 

int main( )

 

 

 

 

 

 

 

{

char* ptr;

 

 

 

 

 

 

 

 

 

о

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

set_new_handler (newhandler);

 

 

 

 

 

 

try {

 

 

и

 

 

 

 

 

 

 

 

л

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

ptr = new char[~size_t(0)/2];

 

 

 

 

 

 

delete[ ] ptr;

 

 

 

 

 

 

 

 

 

 

б

 

 

 

 

 

 

 

 

 

и

 

 

 

 

 

 

 

 

 

Б

 

 

 

 

 

 

 

 

 

 

}

catch( bad_alloc &ba) { cout << ba.what( ) << endl;

}

return 0;

}

Результатом работы программы является

The new_handler is called: bad allocation

176

В слассе new также определена функция _set_new_handler, аргументом которой является указатель на функцию, возвращающую значение типа int и получающую аргумент типа size_t, указывающий размер требуемой памяти:

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

int error_alloc( size_t ) // size_t unsigned integer результат sizeof operator. { cout << "ошибка выделения памяти" <<endl;

return 0;

}

Р

int main( )

{

_set_new_handler( error_alloc );

 

 

 

 

И

int *p = new int[10000000000];

 

 

 

 

return 0;

 

 

 

 

У

}

 

 

 

 

 

 

 

Г

 

Результатом работы функции является:

 

ошибка выделения памяти

 

 

Б

 

 

 

 

 

 

 

В случае, если память не выделяется и не задается никакой функции-

аргумента для set_new_handler, опер тор new генерирует исключение bad_alloc.

 

а

 

 

 

8.4. Генерация исклю ний в

онструкторах

 

 

к

 

 

 

 

Механизм обработки исключительных ситуаций очень удобен для обра-

ботки ошибок, возникающихчев конструкторах. Так как конструктор не возвра-

ходится искать альтернативу. В этом случае наилучшим решением является ге- нерация и обраб тка исключительной ситуации. При генерации исключения

щает значения, то с ве с венно нельзя возвратить некий код ошибки и при-

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

внутри конструкторапроцесс создания объекта прекращается. Если к этому

водный от класса А и содержащий в качестве компоненты-данного объект клас-

 

б

 

 

 

са local. В конструкторе класса В генерируется исключительная ситуация.

и

 

 

 

Б

#include<iostream>

 

using namespace std;

 

class local

 

 

 

 

 

 

 

 

{ public:

 

 

 

 

local()

{

cout<<"Constructor of local"<<endl;

}

 

~local()

{

cout<<"Destructor of local"<<endl;

}

 

};

 

 

 

 

 

 

 

177

178
8.5. Задание собственной функции завершения
}
}
return 0;
}
catch(int) {
cout<<"int exception handler";
int main() { try {
B ob(1);
};
}
~B() { cout<<"Destructor of B"<<endl; }
Результат выполнения программыте: каБГУИР
Constructor of A о Constructor of local Constructor of B и Destructor of localл Destructor of A
int exceptionбhandler
В программеи при создании объекта производного класса В сначала вызыва- ются конструкторы азового класса А, затем класса local, который является компо- нентомБкласса В. После этого вызывается конструктор класса В, в котором генери- руется исключ тельная ситуация. Видно, что при этом для всех ранее созданных объектов вызваны деструкторы, а для объекта самого класса В деструктор не вы- зывается, так как конструирование этого объекта не было завершено.
Если в конструкторах выполнялось динамическое выделение памяти, то при генерации исключительной ситуации выделенная память автоматически ос- вобождена не будет, об этом необходимо заботиться самостоятельно, иначе возникнет утечка памяти.
class B : public A
{ public: local ob; B(int i)
{ cout<<"Constructor of B"<<endl; if(i ) throw 1;
};
{ cout<<"Constructor of A"<<endl; } { cout<<"Destructor of A"<<endl; }
class A
{ public: A() ~A()
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]