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

314

for(i = 0; i < y.SizeArr(); i++) // Заполнение массива y y[i] = rand();

cout << Rus("Количество элементов в y: ") << y.SizeArr(); cout << Rus(", максимальное из y: ") << y.GetMax(); cin.get();

return 0;

}

При одном из запусков программа напечатала:

Количество элементов в x: 64, максимальное из x: 32635 Количество элементов в y: 20, максимальное из y: 30486

21.4. Обработка исключений

Исключение – это особая ситуация, возникающая в ходе работы программы. Встроенными особыми ситуациями являются «деление на нуль», «конец файла», «переполнение при вычислении». В языке C++ любое состояние, достигнутое в процессе выполнения программы, можно заранее определить как особую ситуацию (исключение) и предусмотреть действия, которые нужно выполнить при её возникновении.

Для реализации механизма обработки исключений в языке C++ есть три ключевых слова:

try (пробовать, пытаться, испытывать), catch (ловить, обнаруживать),

throw (бросать, посылать).

Эти ключевые слова позволяют выделить контролируемый блок, зафиксировать исключение и назначить обработчик исключения. Схема обработки исключений имеет вид:

try{

// Контролируемый блок

ОПЕРАТОРЫ

// Обычные операторы

throw ВЫР;

// Передача управления обработчику исключений

ОПЕРАТОРЫ

 

}

catch(ТИП_ИСКЛЮЧЕНИЯ ИМЯ){ // Обработчик исключений ОПЕРАТОРЫ

}

Программист должен предусмотреть передачу управления оператору throw при возникновении исключения. Оператор throw прерывает естественный ход работы программы и передает управление в тот блок catch, у которого ТИП_ИСКЛЮЧЕНИЯ соответствует типу ВЫР, при этом объект ИМЯ инициализируется значением ВЫР.

315

В приводимой ниже программе демонстрируется обработка исключений в задаче о нахождении наибольшего общего делителя двух целых чисел x и y.

Программа 68. Расчет НОД

Справедливы следующие свойства НОД двух чисел: Nod(x, y) = x, если х = у;

Nod(x, y) = Nod(y, x - y), если х > у, Nod(x, y) = Nod(y, x);

если х <= 0, или у <= 0, то Nod не определён.

Исключительными ситуациями при расчете НОД является равенство нулю или отрицательное значение одного из чисел.

Для передачи информации из точки, где возникло исключение в обработчик исключений, введём специальный класс Except, членами которого будут две целые переменные m, n, хранящие значение х и у, и строка mess с сообщением о характере особой ситуации.

//Файл Exeption.cpp #include <iostream.h>

struct Except{

// Класс для информации об исключении

int m, n;

// Числа

char* mess;

// Описание исключения

Except(int a, int b, char* msg) // Конструктор {m = a; n = b; mess = msg;}

};

 

 

int Nod(int x, int y)

 

{

 

 

if(x == 0 || y == 0)

throw Except(x, y, "Zero!");

if(x < 0)

 

throw Except(x, y, "Negative argument 1.");

if(y < 0)

 

throw Except(x, y, "Negative argument 2.");

if(x == y)

return x;

if(x < y)

return Nod(y, x);

return Nod(y, x - y);

}

void main()

{

try{

cout << "\nNod(66, 44) = " << Nod(66, 44)<< '\n'; cout << "\nNod(0, 7) = " << Nod(0, 7)<< '\n'; cout << "\nNod(-12, 8) = " << Nod(-12, 8)<< '\n';

316

}

// Обработчик исключений. В d содержится информация об исключении catch(Except d){

cerr << d.mess << " x = " << d.m << ", y = " << d.n <<'\n';

}

cin.get();

}

Здесь после throw стоит вызов конструктора класса Except, который создаёт безымянный объект, инициализированный значением аргументов Nod и текстом сообщения. Этот объект будет передан в блок catch и использован для инициализации параметра d, тем самым информация об исключении становится доступной в обработчике исключений. Обработка исключения состоит в выводе в поток для ошибок cerr сведений о возникшей проблеме, передаваемых через объект d.

Программа выдает:

Nod(66, 44) = 22

Zero! x = 0, y = 7

Здесь исключение возникает при вычислении Nod(0, 7). Оператор throw прерывает выполнение функции Nod и передает управление в блок catch. Причем отыскивается тот из нескольких возможых блоков catch, которые могут стоять за блоком try, у которого тип объектаисключения соответствует генерируемому типу исключения в операторе throw. Оператор вида

catch(…){

// Обработчик исключений

ИНСТРУКЦИИ

 

}

 

перехватывает исключения любых типов.

21.5. Стандартная библиотека шаблонов

Для обработки данных используются различные структуры данных: массивы, списки, стеки, очереди, множества и т.д. Такая структура данных, как массив, встроена в C++, так же, как и в другие языки программирования. В стандарт C++ входит стандартная библиотека шаблонов STL (Standard Template Library), предназначенная для создания и обработки различных структур данных. В STL содержатся три основные сущности: контейнеры, алгоритмы и итераторы.

317

Контейнер организует хранение данных. Контейнеры STL реализованы в виде шаблонов классов, поэтому обеспечивают хранение как величин базовых типов int, float,…, так и объекты классов. Необходимость в наличии специальных контейнеров вызвана тем, что обычный массив бывает неэффективен, например, часто приходится создавать массивы с запасом, хотя в большинстве случаев память не расходуется полностью.

Контейнеры бывают последовательные и ассоциативные. Последовательными контейнерами являются, например, векторы (vector), списки (list). Ассоциативные контейнеры – это, например, множества (set), отображения или ассоциативные массивы (map). Контейнеры имеют методы, позволяющие работать с ними. Перечислим некоторые:

size() – возвращает текущее число элементов в контейнере; empty() – возвращает true, если контейнер пуст;

max_size() – размер самого большого возможного контейнера; resize() – изменяет размер контейнера (только вектора, списка).

Алгоритмы – это независимые шаблонные функции, не являющиеся членами контейнерных классов, поэтому их можно применять как к классам-контейнерам, так и к обычным массивам. Вот некоторые

алгоритмы:

 

 

 

 

 

find()

находит

первое

вхождение

значения

в

 

последовательность;

 

 

 

count()

подсчитывает количество вхождений данного значения

 

в последовательность;

 

 

 

equal()

возвращает

true,

если

элементы

двух

 

последовательностей попарно равны;

 

search()

находит первое вхождение последовательности как

 

подпоследовательности;

 

 

 

sort()

сортирует последовательность в указном порядке.

 

Итераторы – это обобщение понятия указателей. Итераторы ссылаются на элементы контейнеров и обеспечивают к ним доступ. К итераторам можно применять оператор ++, после выполнения которого итератор будет ссылаться на следующий элемент контейнера. Переход от элемента к элементу называется итерацией. Значение элемента по итератору получается оператором *. В STL итератор представляет собой объект класса iterator.

Для разных типов контейнеров используются свои итераторы. Существует три типа итераторов.

Прямой итератор может проходить по контейнеру только в прямом направлении, к нему применяется оператор ++.

318

Двунаправленный итератор может передвигаться в обоих направлениях и реагирует на операторы ++ и --.

Итератор со случайным доступом может двигаться в обоих направлениях и перескакивать на любой элемент контейнера.

Контейнеры имеют методы, возвращающие итераторы. Приведем для примера два таких метода:

begin() – возвращает итератор на начало контейнера;

end() – возвращает итератор на последнюю позицию в контейнере.

В следующей программе приводится пример использования небольшой части возможностей STL.

Программа 69. Использование шаблона векторов

Термин вектор применяется в STL к динамическим массивам. Шаблон класса векторов vector реализует оператор [] доступа к элементу и оператор присваивания. Вектора из элементов конкретного типа создаются инструкциями вида:

vector <int> Numb(N0);

где Numb – имя создаваемого вектора, N0 – число элементов вектора.

В программе создается вектор с числом элементов N0, затем его размер изменяется до N. Вектор заполняется случайными числами, копируется в другой вектор, который затем сортируется.

// Файл STLVctr.cpp

 

#include <iostream>

 

#include <vector>

 

#include <algorithm>

 

#include <conio.h>

 

using namespace std;

 

const int Max = 1000;

// Максимальное значение элемента массива

const int N0 = 10;

// Первоначальный размер массива

void main()

 

{

 

vector <int> Numb(N0);

// Numb - массив из N0 элементов типа int

int N;

// Количество чисел в массиве

cout << "Input the count of numbers "; // Приглашение ввести размер cin >> N; // Ввод нового размера массива

// size() возвращает текущий размер

if (Numb.size() != N) // Если текущий размер не равен новому, Numb.resize(N); // устанавливаем новый размер

// resize(N) изменяет размер массива на новый, равный N cout << "\nThe Source array\n"; // Исходный массив

 

319

for(int i = 0; i < Numb.size(); i++)

// Заполнение массива случайными

cout << (Numb[i] = rand() % Max) << ' '; // числами и вывод

vector <int> NumbSort(N);

// Еще один массив

NumbSort = Numb; // Новому массиву присваиваем значение старого sort(NumbSort.begin(), NumbSort.end()); // Сортировка массива

//begin() возвращает итератор на первый элемент,

//end() - на последний

cout << "\n The Sorted array\n";

// Отсортированный массив

for(int i = 0; i < NumbSort.size(); i++)

// Вывод отсортированного

cout << NumbSort[i] << ' ';

// массива

getch();

 

}

Далее приведен диалог с программой.

Input the count of numbers 12 The Source array

346 130 982 90 656 117 595 415 948 126 4 558 The Sorted array

4 90 117 126 130 346 415 558 595 656 948 982

Таким образом, STL позволяет легко делать ряд полезных вещей, которые недоступны для базовых типов данных, например, присваивание массивов, их эффективную сортировку и т.п.