69734

Перевантаження операцій new і delete

Домашняя работа

Информатика, кибернетика и программирование

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

Украинкский

2014-10-09

50.5 KB

0 чел.

Самостійне вивчення

Тема 11: Перевантаження операцій new і delete

Щоб забезпечити альтернативні варіанти управління пам'яттю, можна визначати власні варіанти операцій new і new[] для виділення динамічної пам'яті під об'єкт і масив об'єктів відповідно, а також операції delete і delete[] для її звільнення.

Ці функції-операції повинні відповідати наступним правилам:

  1.  їм не вимагається передавати параметр типу класу;
  2.  першим параметром функціям new і new[] повинен передаватися розмір объекта типу size_t (це тип, який повертається операцією sizeof, він визначається в заголовочному файлі <stddef.h>); при виклику він передається у функції неявним чином;
  3.  вони повинні визначатися з типом значення void*, який повертається, навіть якщо return повертає покажчик на інші типи (частіше всього на клас);
  4.  операція delete повинна мати тип повернення void і перший аргумент типу
  5.  void*;
  6.  операції виділення і звільнення пам'яті є статичними элементами класу.

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

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

Стандартні операції виділення і звільнення пам'яті можуть використовуватися в області дії класу разом з перевантаженими (за допомогою операції доступа до області видимості :: для об'єктів цього класу і безпосередньо — для будь-кого інших).

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

class Obj {...};

class pObj{

private:

Obj *p;

};

При виділенні пам'яті під об'єкт типу pObj за допомогою стандартної операції new

pObj *р = new pObj;

фактична кількість байтів перевищуватиме sizeof(pObj), оскільки new звичайно записує в початок області, яка виділяється, її розмір (для того, щоб правильно відпрацьовувала операція delete). Для невеликих об'єктів ці невигідні витрати можуть виявитися вельми впливовими. Для економії пам'яті можна написати власну операцію new класу pObj, яка виділятиме великий блок пам'яті, а потім розміщуватиме в ньому покажчики на Obj. Для цього в об'єкт pObj вводиться статичне поле headOfFree, в якому зберігається покажчик на першу вільну комірку блоку для розміщення чергового об'єкту. Комірки які не використовуються зв'язуються в список. Щоб не позичати пам'ять під поле зв'язку, використовується об'єднання (union), за допомогою якого одна і таж комірка використовується або для розміщення покажчика на об'єкт, або для зв'язку з наступною вільною коміркою:

class pObj

{

public:

static void * operator new(size_t size);

....

private:

union

{

Obj *p;           // Покажчик на об'єкт

pObj *next;   // Покажчик на наступну вільну комірку

};

static const int BLOCK_SIZE; // Розмір блоку

// Заголовок списку вільних комірок:

static pObj *headOfFree;

};

void * pObj::operator new(size_t size)

{

// Перенаправити запити невірної кількості пам'яті

// стандартної операції new:

if (size != sizeof(pObj)) return ::operator new(size);

pObj *p  headOfFree; // Покажчик на першу вільну комірку

// Перемістити покажчик списку вільних комірок:

if (p) headOfFree = р -> next;

// Якщо вільної пам'яті немає, виділяємо черговий блок:

else {

pObj *newblock = static_cast<pObj*>

(::operator new(BLOCK_SIZE * sizeof(pObj)));

// Всі комірки вільні, окрім першої (вона буде

// зайнята), зв'язуємо їх:

for (int i=1; і<BLOCK_SIZE-1;++j) newblock[i].next = &newblock[i+1];

newblock[BLOCK_SIZE - l].next = 0;

// Встановлюємо початок списку вільних комірок:

headOfFree = &newblock[l];

р = newblock;

} return p; // Повертаємо покажчик на виділену пам'ять

}

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

В програмі, яка використовує клас pObj, повинна бути присутня ініціалізація його статичних полів

pObj *pObj::headOfFree;    // Встановлюється в 0 за замовчуванням

const int pObj::BLOCK_SIZE = 1024;

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

Природно, що якщо операція new перевантажена, то ж саме повинне бути зроблено і для операції delete (наприклад, в нашому випадку стандартна операція delete не знайде на початку об'єкту вірної інформації про його розміри що приведе до невизначеної поведінки програми).

В розглянутому прикладі операція delete повинна додавати звільнений елемент пам'яті до списку вільних комірок:

void pObj::operator delete(void * ObjToDie. size_t  size)

{

if (ObjToDie == 0) return;

if (size != sizeof(pObj))

{

::operator delete(ObjToDie);

return;

}

pObj *p= static_cast<pObj*>(ObjToDie);

p->next = headOfFree;

headOfFree = p;

}

В операції delete виконана перевірка відповідності розмірів об'єктів, аналогічна приведеної в операції new.

Перевантаження операції приведення типу

Можна визначити функції-операції, які здійснюватимуть перетворення об'єкту класу до іншого типу. Формат:

operator ім'я_нового_типу();

Тип значення, яке повертається, і параметри вказувати не вимагається. Можна визначати віртуальні функції перетворення типу. Приклад:

monstr::operator int(){return health;}

monstr Vasia;

cout << int(Vasia);

Перевантаження операції виклику функції

Клас, в якому визначена операція виклику функції, називається функціональним. Від такого класу не вимагається наявності

інших полів і методів:

class if_greater

{

public:

int operator() (int а, int b) const

{

return а > b;

}

};

Використання такого класу має вельми специфічний синтаксис. Наприклад:

if_greater x;

cout << х(1,5)<< endl;                       // Результат - 0

cout << if_greater()(5,1) << endl;     // Результат - 1

Оскільки в класі if_greater визначена операція виклику функції з двома параметрами, вираз х(1,5) є допустимим (те ж саме можна записати у вигляді х.operator()(1, 5)). Як видно з прикладу об'єкт функціонального класу використовується так, якби він був функцією.

В другому операторі виведення вираз if_greater() використовується для виклику конструктора за замовчуванням класу if_greater.

Результатом виконання цього виразу є об'єкт класу if_greater. Далі, як і в попередньому випадку, для цього об'єкту викликається функція з двома аргументами, записаними в круглих дужках.

Операцію () можна визначати тільки як метод класу. Можна визначити перевантажені операції виклику функції з різною кількістю аргументів. Функціональні об'єкти широко застосовуються в стандартній бібліотеці C++.

Перевантаження операції індексації

Операція індексації [ ] звичайно перевантажується, коли тип класу представляє безліч значень, для якої індексація має сенс. Операція індексації повинна повертати посилання на елемент, який міститься в множині.Приклад класу Vect, призначеного для зберігання массива цілих чисел і безпечної роботи з ним:

#iinclude <iostream.h>

#iinclude <stdlib.h>

class Vect

{

public:

explicit Vect(int n = 10);

Vect(const int а[ ], int n); //ініціалізація масивом

~Vect() { delete [ ] p; }

int &operator [ ](int i);

void Print();

private:

int *p;

int size;

};

Vect::Vect(int n):Size(n)

{

p = new int[size];

};

Vect::Vect(const int a[], int n) : size(n)

{

p = new int[size];

for (int і = 0; і < size; i++)

p[i] - а[i];

}

// Перевантаження операції індексації:

int& Vect::operator [] (int i)

{

if(i < 0 || і >= size)

{

cout << "Невірний індекс (і = " << і << ")" << endl;

cout << "Завершення програми" << endl;

exit(0);

};

return p[i];

};

void Vect::Print()

{

for (int і = 0; і < size; i++)

cout << p[i]<< " "; cout << endl;

}

int main()

{

int arr[10]= {1, 2, 3, 4,  5, 6,  7, 8.  9,  10};

Vect а(arr,10);

а.Print();

cout << а[5]<< endl;

cout << а[12]<< endl;

return 0;

}

Результат роботи програми:

1 2 3 4 5 6 7 8 9 10

6

Невірний індекс (і = 12)

Завершення програми

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

В даному прикладі конструктор з параметром за замовчуванням оголошений як explicit для того, щоб він не був конструктором перетворення типу який викликається неявно. Ключове слово explicit вказує на те, що цей конструктор викликатиметься тільки явним чином. Операцію [] можна визначати тільки як метод класу.


 

А также другие работы, которые могут Вас заинтересовать

52515. Тексти для диктантів в 5 – 9 класах. Найбільше багатство – здоров’я 127 KB
  Боріться за здорове життя Тому головним девізом у кожного з нас повинен бути: постійний контроль і аналіз власних вчинків Пояснювальний диктант Пояснити правопис слів з подвоєними приголосними звуками Дбай про фізичну культуру. Диктант по памяті Визначити іменники та дієслова Біг сприяє розвитку легенів укріплює серцевий мяз сприяє обміну речовин позитивно впливає на нервовий стан. Коментований диктант Написання слів з подвоєними приголосними звуками правопис ь ьо апострофа Плавання покращує діяльність серцево ...
52516. Збірник диктантів з української мови 5 клас За матеріалами підручника Р. Мовчан «Українська література» 103.5 KB
  Окрім того можна доповнити диктанти іншими видами діяльності. Пояснювальні диктанти. Творчі диктанти Утворіть словосполучення з поданими словами. Пояснювальні диктанти
52517. Літературні диктанти 169.5 KB
  Учень відразу ж записує у зошит відповіді на запитання вчителя. Лінійні диктанти полегшують діяльність учнів тим що остання літера кожного слова відповіді є першою літерою наступного слова. Зразки літературних диктантів 5 клас Народна казка “Мудра дівчина†Акродиктант Якщо ви правильно дасте відповіді на всі питання то з других літер сліввідповідей складете словощо вкаже різновид казки “Мудра дівчинаâ€. Що в світі прудкіш над усе Скільки ліктів полотна...
52518. Типи і приклади літературних диктантів 594.5 KB
  Літературними диктантами називаються такі види роботи які дають змогу швидко і різнобічно перевірити знання учнів з теми що вивчається. Літературні диктанти подібні до тестових завдань. Літературні диктанти як правило можуть проводитись на початку уроку перевірка домашнього завдання актуалізація опорних знань чи в його кінці підсумок узагальнення виконуються в зошитах чи на окремих аркушах можливе їх...
52519. Усі уроки географії у 6 класі 3.11 MB
  Посібник містить розробки усіх уроків географії у 6 класі за Програмою 12-річної школи із використанням сучасних методів та прийомів навчання. Особливу увагу автор приділив рекомендаціям щодо проведення етапу мотивації, а також варіативності завдань для актуалізації та закріплення. Пропонуються також додаткові матеріали, завдання творчого рівня.
52520. Усі уроки географії. 7 клас 1.61 MB
  Посібник підготовлено відповідно до нової програми Міністерства освіти і науки України. Він представляє собою детальні розробки уроків відповідно до авторського календарного планування, причому кілька тем уроків представлені двома альтернативними варіантами. Для кожного уроку зазначено: мету, як навчальну з предмета, так і виховну, розвивальну; тип; найдоступніше обладнання; опорні та базові поняття; об’єкти географічної номенклатури.
52521. Усі уроки географії. 8 клас 1.16 MB
  Завершальним етапом роботи учнів на уроці є підсумок уроку. Здебільшого пропонуються прийоми, які дозволяють учням зробити його самостійно. Розробку уроку завершують різні види домашнього завдання. Представлені уроки тематичного оцінювання, завдання яких складені подібно до завдань, які використовувались під час ЗНО, відповідають програмним вимогам щодо знань і вмінь.
52522. Ділення раціональних чисел 153.5 KB
  Обладнання: фізична карта світу макет козацької чайки піратського корабля сигнальні картки карткизавдання; підручник для 6го класу: Математика Мерзляк А. Щоб зорієнтуватися в просторі нам треба розвязати завдання за правильними відповідями відшукати слово яке вкаже на курс нашої подорожі. ІІІ етап Поповнення запасів їжі і питної води Робота з сигнальними картками: Тестові завдання учні підіймають картку з правильною на їх думку відповіддю...
52523. Найбільший спільний дільник кількох чисел ( НСД) 34 KB
  Мета: сформулювати поняття спільного дільника кількох чисел найбільшого спільного дільника взаємно простих чисел; домогтися засвоєння алгоритму знаходження НСД кількох чисел. Коротко це можна записати так: НСД45, 30 = 15. Для довільних чисел і b пишуть так НСД; b.