Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Не підтверджено.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
3.08 Mб
Скачать

Int mainO

{

int *р;

try {

р = new int[32]; // Запит на виділення області пам'яті // для 32-елементного int-масиву

}

catch(bad_alloc ха) {

cout « "Пам'ять не виділена" « endl; return 1 ;

}

for(int і=0; і<32; І++) р[і] = і;

for(int i=0; i<32; i++) cout « P[i]

delete [] p; // Звільнення пам'яті

getchO; return 0;

}

Під час невдалого виконання оператора new виняток у цьому коді програми буде перехоплено catch-настановою. Цей самий підхід можна використовувати для вистежування будь-яких помилок, взаємопов'язаних з використанням опера­тора new: достатньо помістити кожну new-настанову в try-блок.

Альтернативна форма оператора new - nothrow. Стандарт мови C++ при невдалій спробі виділення області пам'яті оператором new замість генерування ви­нятку також може повертати значення NULL. Ця форма використання оператора new особливо корисна у процесі компілювання старих програм із застосуванням сучасного С++-компілятора. Вона також корисна при заміні викликів функції mal- Іос() оператором new. Це звичайна практика у процесі перекладу С-коду програми на мову програмування C++. Отже, формат оператора new має такий вигляд: p_var = new(nothrow) muir,

У цьому записі елемент p_var - це покажчик на змінну типу тип. Цей nothrow- формат оператора new працює подібно до оригінальної версії оператора new, яка використовувалася кілька років тому. Оскільки оператор new(nothrow) повертає при невдачі значення NULL, його можна "упровадити" в старий код програми, не вдаючись до оброблення винятків. Проте в нових програмах, написаних мовою C++, все ж таки краще мати справу з генеруванням винятків.

У наведеному нижче прикладі показано, як використовується альтернатив­ний варіант new(nothrow). Неважко здогадатися, що нижче наведено можливий ва­ріант попереднього коду програми.

Код програми 8.13. Демонстрація механізму використання nothrow як старої версії оператора new #include <iostream> // Для потокового введення-виведення

#include <new> // Для перевизначення операторів new і delete

using namespace std; // Використання стандартного простору імен

Int mainO

{

int *р;

р = new(nothrow) int[32]; // Використання nothrow-версії if№){

cout « "Пам'ять не виділена" « endl; return 1;

}

for(int i=0; i<32; І++) p[i] = i; for(int i=0; i<32; І++) cout « P[i] delete [] p; // Звільнення пам'яті getchO; return 0;

}

У цьому коді програми під час використання throw-версії після кожного запи­ту на виділення області пам'яті необхідно перевіряти значення покажчика, що по­вертається оператором new.

  1. Механізми перевизначення операторів new і delete

Оскільки new і delete - оператори, то їх також можна перевизначати. Хоча те­ма перевизначення операторів new і delet розглядалася в розд. 4 [9], проте деяка їх частина була відкладена до знайомства з темою оброблення винятків, оскільки правильно перевизначений оператор new (який відповідає стандарту мови C++) повинен у разі невдачі генерувати виняток типу bad_alloc. З кількох причин Вам варто створити власну версію оператора new. Наприклад, створіть процедури виді­лення області пам'яті, які, якщо область множини виявиться вичерпаною, автома­тично починають використовувати дисковий файл як віртуальну пам'ять. У будь- якому випадку реалізація перевизначення цих операторів є не складнішою за пе- ревизначення будь-яких інших.

Нижче наведено скелет функцій, які перевизначають оператори new і delete.

// Виділення області пам'яті для об'єкта void ‘operator new(size_t size)

{

/* У разі неможливості виділити пам'ять генерується виняток

типу bad_alloc. Конструктор викликається автоматично. */

return pointer_to_memory;

}

// Видалення об'єкта, void operator delete(void *р)

{

І* Звільняється область пам'яті, яка адресується покажчиком р.

Деструктор викликається автоматично. */

}

Тип size_t спеціально визначено, щоб забезпечити зберігання розміру макси­мально можливої області пам'яті, яку можна виділити для об'єкта1. Параметр size визначає кількість байтів пам'яті, потрібної для зберігання об'єкта, для якого виді­ляється пам'ять. Іншими словами, це об'єм пам'яті, який повинна виділити Ваша версія оператора new. Операторна функція new повинна повертати покажчик на пам'ять, що виділяється нею, або генерувати винятки типу bad_alloc у випадку ви­никнення помилки. Окрім цих обмежень, операторна функція new може виконува­ти будь-які потрібні дії. Під час виділення області пам'яті для об'єкта за допомо­гою оператора new (його початкової форми або Вашої власної) автоматично вик­ликається конструктор об'єкта.

Функція delete отримує покажчик на область пам'яті, яку необхідно звільнити. Потім вона повинна повернути цю область пам'яті системі. Під час видалення об'­єкта автоматично викликається його деструктор.

Щоб виділити пам'ять для масиву об'єктів, а потім звільнити її, необхідно ви­користовувати такі формати операторів new і delete.

// Виділення області пам'яті для масиву об'єктів void ‘operator new[](size_t size)

{

/* У разі неможливості виділити пам'ять генерується виняток

типу bad_alloc. Кожен конструктор викликається автоматично. */

return pointer_to_memory;

// Видалення масиву об'єктів, void operator delete[](void *р)

Iі Звільняється область пам'яті, яка адресується покажчиком р. При цьому автоматично викликається деструктор для кожного елемента масиву. */

Під час виділення області пам'яті для масиву автоматично викликається конструктор кожного об'єкта, а при звільненні масиву автоматично викликається деструктор кожного об'єкта. Це означає, що для виконання цих дій не потрібно безпосередньо програмувати їх.

Оператори new і delete, як правило, перевизначаються відносно класу. Заради простоти у наведеному нижче прикладі використовується не нова схема розподілу пам'яті, а перевизначені функції new і delete, які просто викликають С-орієнтовані функції виділення області пам'яті mallocO і free(). У своєму власному додатку Ви можете реалізувати будь-який метод виділення області пам'яті.

Щоб перевизначити оператори new і delete для конкретного класу, достатньо зробити ці перевизначені операторні функції членами цього класу. У наведеному нижче прикладі коду програми оператори new і delete перевизначаються для класу kooClass. Це перевизначення дає змогу виділити пам'ять для об'єктів і масивів об'­єктів, а потім звільнити її.

Код програми 8.14. Демонстрація механізму перевизначення операторів

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

new і delete

// Для потокового введення-виведення // Для перевизначення операторів new і delete // Для використання бібліотечних функцій // Використання стандартного простору імен

class kooClass {// Оголошення класового типу int х, у, z; // Тривимірні координати public:

kooClass() {х = у = z = 0; cout«"Створення об'єкта 0,0, 0" « endl;} kooClass(int с, int d, int f) {х = с; у = d; z = f; cout«"Створення об'єкта" « c «", cout« d «"," «f« endl;}

-kooClassO {cout«"Руйнування об'єкта" « endl;} void ‘operator new(size_t size); void ‘operator new[](size_t size); void operator delete(void *p); void operator delete[](void *p); void showB(char*s);

};

// Перевизначення оператора new для класу kooClass. void *kooClass::operator new(size_t size)

{