1.4b

advertisement
ПРЕЗЕНТАЦИЯ НА ТЕМУ:
ОБРАБОТКА ИСКЛЮЧЕНИЙ
Выполнил: Волков И.К.
Гр.271ПИ
Вступление

Во многих отношениях, обработка исключения в C ++ близко
напоминает обработку исключения в Java. Прежде всего, C ++
использует тот же самый механизм блока Try-catch, используемый в
Java. Кроме того, оба языка также обеспечивают иерархию класса
исключения, которую программисты могут использовать и
расширять. Мы исследуем, как неправильное управление памяти
усложняет обработку исключений.
 Обработка исключений в С++ основывается на использовании 2
ключевых слов, try и catch. Программист прилагает код, который
может вызвать исключение в пределах блока try. Один или более
блоков catch немедленно следуют за блоком try. Когда исключение
происходит в блоке try, выполнение программы передается блоку
catch, соответствующему типу вызванного исключения. Блок catch
выполняет необходимые задачи избавления от исключительного
условия. Другими словами, он «обрабатывает, решает проблему» с
исключением. Пример 1 демонстрирует использование блоков try и
catch в C ++. См. Пример 1.

ПРИМЕР 1 Блоки Try и Catch
#include <iostream>

#include <cstdlib>

#include <stdexcept>

using namespace std;

void calculate_fibonacci(int);

int main(int argc, char* argv[]) {

try {

if (argc != 2) {

cerr << "Usage: " << argv[0] << " num" << endl;

return EXIT_FAILURE;

}

int number_fib = atoi(argv[1]);

calculate_fibonacci(number_fib);

19:

return EXIT_SUCCESS;

}

catch (exception& e) {

cerr << e.what() << endl;

}

return EXIT_FAILURE;

}

void calculate_fibonacci(int number_fib) {

int* array = new int[number_fib];

array[0] = 1;

array[1] = 1;

// populate the elements with Fibonacci numbers

for (int i = 2; i < number_fib; i++) {

array[i] = array[i - 1] + array[i - 2];

}

delete [] array;
 Программисты C ++ вызывают исключения,
используя оператор Throw. В Throw,
программист определяет тип вызываемого
исключения, для использование
последующего throw. В примере 2
беспорядочно вызывается одно из двух
исключений, используя оператор throw.
См. пример 2

ПРИМЕР 2 Вызов исключений

#include <iostream>
#include <cstdlib>
#include <stdexcept>
#include <ctime>
using namespace std;
int main(int argc, char* argv[]) {
try {
srand(time(0));
if (rand() % 2 == 0) {
throw out_of_range("out of range");
}
else {
throw length_error("length error");
}
return EXIT_SUCCESS;
}
catch (out_of_range e) {
cerr << "caught out_of_range exception" << endl;
}
catch (length_error e) {
cerr << "caught length_error exception" << endl;
}
return EXIT_FAILURE;
}























 В C ++, переменная любого типа данных может быть
объектом исключений, переданным оператором throw.
C ++ может передавать в исключении объекты
определенных пользователем классов, объекты
стандартных классов и даже переменные
фундаментальных типов данных. Как правило, никто не
использует основные объекты и фундаментальные типы
данных как исключения. C ++ программисты вместо
этого создают определенные пользователем классы
исключения. Мы исследуем это позже.
 Функция может передать выполнение оператору catch,
существующему в другой функции. Это обычно
случается, когда функцию (которая передает
исключение) вызывают изнутри блока try другой
функции. См. Пример 3.

ПРИМЕР 3 Обработка вызванного исключения в другой функции

#include <iostream>
#include <cstdlib>
#include <stdexcept>
using namespace std;
void display_args(int argc, char* argv[]) {
if (argc == 1) {
throw runtime_error("Please supply arguments");
}
for (int i = 1; i < argc; i++) {
cout << argv[i] << endl;
}
}
int main(int argc, char* argv[]) {
try {
display_args(argc, argv);
return EXIT_SUCCESS;
}
catch (runtime_error& e) {
cerr << e.what() << endl;
}
return EXIT_FAILURE;
}





















 C ++ использует механизм, способный
обработать исключения всех возможных
типов. Блок catch, аргумент которого
содержит «…», обрабатывает все
исключения. Это полезно в ситуациях,
когда программист хочет быть уверенным,
что все возможные исключения
обработаны. Необработанное исключение
может вызвать неправильную работу
программы. См. Пример 4
 ПРИМЕР 4 «Отлов» всех исключений
 int main(int argc, char* argv[]) {
 try {
 if (argc == 1) {
 throw runtime_error("runtime error");
 }
 if (argc == 2) {
 throw out_of_range("out of range");
 }
 if (argc == 3) {
 throw length_error("length error");
 }
 return EXIT_SUCCESS;
 }
 catch (...) {
 cerr << "An exception was caught!" << endl;
 }
 return EXIT_FAILURE;
Стандартная Иерархия
Исключений C ++
 Стандартная Библиотека С++ содержит и
использует стандартную иерархию
классов исключений. Классы,
содержащиеся в этой иерархии
вызываются различными компонентами
языка C ++, Стандартной Библиотекой и
Стандартной Библиотекой Шаблонов.
Иллюстрация 1 изображает стандартную
иерархию исключений(См. Иллюстрацию
1)
Иллюстрация 1
Стандартная иерархия исключений
 Bad_alloc и out_of_range исключения - два
стандартных исключения, на которые нужно
обращать внимание. Исключение bad_alloc
вызывается новым оператором всякий раз, когда
память не может быть предоставлена согласно
запросу. Исключение out_of_range вызывается
функцией члена at типа vector, когда требуется
элемент, индекс которого вне диапазона s.
 Обработка стандартных объектов исключений
позволяет программисту работать с ними
используя полиморфизм. Это полезно, так как это
позволяет блоку catch обращаться со всеми
исключениями стандартной иерархии
исключений. Например, обработка класса
runtime_error обрабатывает исключения типа
runtime_error и всех подтипов.

Интерфейсы стандартных классов иерархии исключения содержат
член-функцию what. Эта функция возвращает строку, описывающую
тип объекта вызова исключения. Работа с объектами исключения на
основе полиморфизма лучше, так как она обеспечивает стандартный
механизм сообщений относительно динамического типа объекта
исключений. Чтобы увидеть значение функции what, запустите
программу примера 1 с аргументом 1000000000 (один миллиард).
Исключение Bad_alloc будет вызвано, так как программа будет не в
состоянии запросить достаточно памяти, чтобы хранить миллиард
целых чисел. См. Пример 5.

Пример 5 Полиморфичный отлов исключений
try {
// some code ...
}
catch (runtime_error& e) {
// catch all runtime errors
cerr << e.what() << endl;
}
catch (logic_error& e) {
// catch all logic errors
cerr << e.what() << endl;
}
catch (exception& e) {
// catch all the rest of the exceptions
cerr << e.what() << endl;
}















 Программисты могут расширить стандартную
иерархию исключений, определяя их
собственные классы, которые наследуются от
одного из стандартных классов исключений.
См. Пример 6
 Пример 6 Расширение стандартной иерархии
исключения





class DivideByZeroException : public logic_error {
public:
DivideByZeroException(const string& what_arg ) throw()
: logic_error ("divide by zero: " + what_arg) {}}
;
 С точки зрения программной инженерии, расширение
стандартной иерархии исключений пользовательскими
классами является хорошей практикой. Это позволяет
программисту работать с определенными пользователем
исключениями и стандартными исключениями одинаково,
так как они оба наследуют тот же самый интерфейс.
Определенные пользователем классы исключения также
полезны, так как они могут быть запрограммированы, чтобы
хранить информацию о состоянии программы, когда
исключение вызвано.
 Спецификация исключений определяет типы исключений,
которые программа может вызвать. В C ++, мы можем
определить, что функция вызывает один или более
определенных исключений, все типы исключений или ничего
не вызывает. Следующий пример демонстрирует различные
использования спецификаций исключения.
 Пример 7 Спецификация исключений





// Some function declarations
void f() throw(); // throws no exceptions
void g() throw(out_of_range); // throws one
void h() throw(out_of_range, bad_alloc); // throws two
void i(); // can throw any exception (the default)
 Программисты C ++ должны использовать
спецификации исключения экономно, так как
они выставляют информацию о выполнении
функции. Дочерний класс может отрицать
выполнение наследованных функций,
которые имеют спецификации исключения.
Наследованные спецификации исключения
могут не обращаются к дочернему
выполнению класса. Возможно,что
выполнение дочернего класса должно
вызвать исключение out_of_range , когда
родительский класс вызывает только
исключение length_error.
 Функция main программы, которая работает с
исключениями, используя стандартную иерархию
исключений, должна следовать стандартным форматам.
Следующий исх. код содержит пример этого формата. В этом
формате, единственный try-блок содержит основной
исходный код. После этого try-блока следуют несколько
блоков catch. Catch-Блоки следуют в порядке убывания
определенности обрабатываемых исключений. Это
позволяет программисту предпринимать определенные
действия для конкретных исключений. Отлов исключений
класса гарантирует, что все определенные пользователем и
стандартные классы иерархии исключения пойманы.
Наконец, все исключения пойманы для того, чтобы
гарантировать штатное завершение программы, если
нестандартное исключение вызвано где-нибудь в
приложении. См. Пример 8.


















Пример 8 обработка исключений
int main(int argc, char* argv[]) {
try {
// source ...
return EXIT_SUCCESS;
}
catch (out_of_range& e) { // specific
cerr << "Out of range" << endl;
}
catch (exception& e) { // general
cerr << e.what() << endl;
}
catch (...) { // all
cerr << "A non-standard exception" <<
" was caught!" << endl;
}
return EXIT_FAILURE;
}
Промежуточные обработчики
 Промежуточные обработчики исключений –
обработчики, которые ловят исключения,
освобождают некоторый ресурс, и
немедленно повторно вызывают исключение.
Промежуточные обработчики исключений
используются, чтобы гарантировать, что вся
используемая память должным образом
освобождена, даже когда программа
передает контроль обработчику исключений.
Это усложняется, когда программа передает
контроль блоку catch в различных функциях.
См.Пример 9
 Пример 9 Утечка памяти при обработке исключений

#include <iostream>

#include <cstdlib>

#include <stdexcept>

using namespace std;

void method_two() {

throw out_of_range("out of range");

}

void method_one() {

int *array = new int[100];

method_two();

delete [] array;

}

int main(int argc, char* argv[]) {

try {

method_one();

return EXIT_SUCCESS;

}

catch (exception& e) {

cerr << e.what() << endl;

}

catch (...) {

cerr << "Unknown exception!" << endl;

}

return EXIT_FAILURE;

}

Вышеупомянутый пример иллюстрирует трудность, которую
обработка исключений вызывает в управлении памяти и почему мы
должны использовать обработчики исключений. Этот пример
включает функцию method_one, которая располагает массив целых
чисел в памяти. Прежде, чем method_one освобождает этот массив,
функция вызывает method_two. Функция method_two немедленно
вызывает исключение. Тогда контроль передается самому близкому
соответствующему Сatch-блоку. Этот catch-блок, однако,
расположен в главной функции. Передача контроля обратно catchблоку пропускает удаление массива, выполненное в method_one.
Это приводит к утечке памяти. Промежуточный обработчик
исключений может предотвратить утечку памяти, которая
присутствует во Примере 9. Работа такого обработчика должна
поймать любое исключение, вызванное внутри method_two,
освободить массив целых чисел, и повторно вызвать исключение.
Пример 10 включает такой обработчик исключений.
 Пример 10 Промежуточный обработчик исключений

#include <iostream>

#include <cstdlib>

#include <stdexcept>

using namespace std;

void method_two() {

throw out_of_range("out of range");

}

void method_one() {

int *array = new int[100];

try {

method_two();

delete [] array;

}

catch (...) {

delete [] array;

throw; // rethrow exception

}

}

int main(int argc, char* argv[]) {

try {

method_one();

return EXIT_SUCCESS;

}

catch (exception& e) {

cerr << e.what() << endl;

}

catch (...) {

cerr << "Unknown exception!" << endl;

}

return EXIT_FAILURE;

}
 Спасибо за внимание!
Download