Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лекции C++.doc
Скачиваний:
7
Добавлен:
01.05.2025
Размер:
1.44 Mб
Скачать

6.1.1 Перехват всех исключений

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

catch(...)

{

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

}

Здесь многоточие соответствует любому типу данных.

Следующая программа иллюстрирует использование catch (...):

#include <iostream.h>

void x_handler(int test)

{

try

{

if(test==0) throw test; // генерация int

if(test==1) throw 'a'; // генерация char

if(test==2) throw 123.23; // генерация double

}

catch(...)

{

cout << "Caught exception!\n";

}

}

int main()

{

cout << "Start\n";

x_handler(0);

x_handler(1);

x_handler(2);

cout << "End";

return 0;

}

Программа выведет на экран следующий текст:

Start

Caught exception!

Caught exception!

Caught exception!

End

Как можно видеть, три инструкции throw были перехвачены с использованием одной инструкции catch.

6.2 Работа с памятью с помощью new и delete

Как известно, в языке С для динамического выделения и освобождения памяти используются фун­кции malloc() и free(). Кроме них C++ содержит два оператора, выполняющих выделение и освобождение памяти более эффективно и более просто. Этими операторами являются new и delete. Их общая форма имеет вид:

переменная_указатель = new тип_переменной;

delete переменная_указатель;

Здесь переменная_указатель является указателем типа тип_переменной. Оператор new выделяет память для хранения значения типа тип_пережнной и возвращает ее адрес. С помощью new могут быть размещены любые типы данных. Оператор delete освобождает память, на которую указывает указатель переменная_указатель.

Если операция выделения памяти не может быть выполнена, то возможны два варианта поведения оператора new. Поведение по умолчанию состоит в том, что оператор new генерирует исключение типа bad_alloc. Второй вариант поведения new в случае ошибки состоит в том, что оператор new возвращает значение NULL, т.е. нулевой указатель. Поскольку второй вариант является нестандартным поведением оператора new, для его использования необходимо предварительно один раз вызвать функцию set_new_handler() с нулевым значением в качестве аргумента. Кроме того, необходимо включить в программу заголовочный файл new.h. В следующих примерах будут рассмотрены оба варианта обработки ошибок оператора new.

Оператор delete следует использовать только для указателей на память, выделенную с исполь­зованием оператора new. Использование оператора delete с другими типами адресов может по­родить серьезные проблемы.

Есть ряд преимуществ использования new перед использованием malloc(). Во-первых, оператор new автоматически вычисляет размер необходимой памяти. Нет необходимости в использовании оператора sizeof(). Более важно то, что он предотвращает случайное выделение неправильного количества памяти. Во-вторых, оператор new автоматически возвращает указатель требуемого типа, так что нет необходимости в использовании оператора преобразования типа. В-третьих, как ско­ро будет описано, имеется возможность инициализации объекта при использовании оператора new. И наконец, имеется возможность перегрузить оператор new и оператор delete глобально или по отношению к тому классу, который создается.

Ниже приведен простой пример использования операторов new и delete.

#include <iostream.h>

int main()

{

int *p;

try

{ // обрабатываем возможное исключение оператора new

p = new int; // выделение памяти для одной переменной типа int

}

catch(bad_alloc a) // также можно писать catch(...)

{

cout << "Allocation failure.\n";

return 1;

}

*p = 20; // присвоение данному участку памяти значения 20

cout << *p; // демонстрация работы путем вывода значения

delete p; // освобождение памяти

return 0;

}

Эта программа присваивает переменной p адрес блока памяти, имеющего достаточный размер для того, чтобы содержать число целого типа. Далее этой памяти присваивается значение 20 и содер­жимое памяти выводится на экран. Наконец, динамически выделенная память освобождается.

Как отмечалось, можно инициализировать память с использованием оператора new. Для этого надо указать инициализирующее значение в скобках после имени типа. Например, в следующем примере память, на которую указывает указатель p, инициализируется значением 99:

#include <iostream.h>

#include <new.h>

int main()

{

int *p;

set_new_handler(0); // оператор new будет возвращать NULL при ошибке

p = new int(99); // инициализация 99-ю

if(!p) { cout << "Allocation failure.\n"; return 1; }

cout << *p;

delete p;

return 0;

}

С помощью new можно размещать массивы. Общая форма для одномерного массива имеет вид:

переменная_указатель = new тип_переменной[размер];

Здесь размер определяет число элементов в массиве. Необходимо запомнить важное ограничение при размещении массива: его нельзя инициализировать.

Для освобождения динамически размещенного массива необходимо использовать следующую форму оператора delete:

delete [] переменная_указатель;

Здесь скобки [] информируют оператор delete, что необходимо освободить память, выделенную; для массива.

В следующей программе выделяется память для массива из 10 элементов типа float. Элементам массива присваиваются значения от 100 до 109, а затем содержимое массива выводится на экран:

#include <iostream.h>

int main()

{

float *p;

int i;

set_new_handler(0);

p = new float[10]; // выделение памяти для массива из 10 элементов

if(!p) { cout << "Allocation failure.\n" ; return 1; }

for(i=0; i<10; i++) p[i] = 100.00 + i;

for(i=0; i<10; i++) cout << p[i] << " ";

delete [] p; // удаление всего массива

return 0;

}