// Обработка исключений, генерируемых оператором new.
#include
#include
using namespace std;
int main()
{
int *p, i;
try {
p = new int[32]; // запрос на выделение памяти для 32-элементного int-массива
}
catch (bad_alloc ха) {
cout << "Память не выделена.\n";
return 1;
}
for(i=0; i<32; i++) p[i] = i;
for(i=0; i<32; i++ ) cout << p[i] << " ";
delete [] p; // освобождение памяти
return 0;
}
При неудачном выполнении оператора new
исключение в этой программе будет перехвачено catch-инструкцией. Этот же подход можно использовать для отслеживания любых ошибок, связанных с использованием оператора new: достаточно заключить каждую new-инструкцию в try-блок.Альтернативная форма оператора new — nothrow Стандарт C++ при неудачной попытке выделения памяти вместо генерирования исключения также позволяет оператору new
возвращать значение null. Эта форма использования оператора new особенно полезна при компиляции старых программ с применением современного С++-компилятора. Это средство также очень полезно при замене вызовов функции malloc() оператором new. (Это обычная практика при переводе С-кода на язык C++.) Итак, этот формат оператора new выглядит следующим образом.
p_var = new(nothrow) тип;
Здесь элемент p_var
— это указатель на переменную типа тип. Этот nothrow-формат оператора new работает подобно оригинальной версии оператора new, которая использовалась несколько лет назад. Поскольку оператор new (nothrow) возвращает при неудаче значение null, его можно "внедрить" в старый код программы, не прибегая к обработке исключений. Однако в новых программах на C++ все же лучше иметь дело с исключениями.В следующем примере показано, как используется альтернативный вариант new (nothrow)
. Нетрудно догадаться, что перед вами вариация на тему предыдущей программы.
// Использование nothrow-версии оператора new.
#include
#include
using namespace std;
int main()
{
int *p, i;
p = new(nothrow) int[32]; // использование nothrow-версии
if(!p) {
cout << "Память не выделена.\n";
return 1;
}
for(i=0; i<32; i++) p[i] = i;
for(i=0; i<32; i++ ) cout << p[i] << " ";
delete [] p; // освобождение памяти
return 0;
}
Здесь при использовании nothrow
-версии после каждого запроса на выделение памяти необходимо проверять значение указателя, возвращаемого оператором new.Перегрузка операторов new и delete
Поскольку new
и delete — операторы, их также можно перегружать. Несмотря на то что перегрузку операторов мы рассматривали в главе 13, тема перегрузки операторов new и delete была отложена до знакомства с темой исключений, поскольку правильно перегруженная версия оператора new (та, которая соответствует стандарту C++) должна в случае неудачи генерировать исключение типа bad_alloc. По ряду причин вам имеет смысл создать собственную версию оператора new. Например, создайте процедуры выделения памяти, которые, если область кучи окажется исчерпанной, автоматически начинают использовать дисковый файл в качестве виртуальной памяти. В любом случае реализация перегрузки этих операторов не сложнее перегрузки любых других.Ниже приводится скелет функций, которые перегружают операторы new
и delete.
// Выделение памяти для объекта.
void *operator new(size_t size)
{
/* В случае невозможности выделить память генерируется исключение типа bad_alloc. Конструктор вызывается автоматически. */
return pointer_to_memory;
}
// Удаление объекта.
void operator delete(void *p)
{
/* Освобождается память, адресуемая указателем р. Деструктор вызывается автоматически. */
}