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 вказує на те, що цей конструктор викликатиметься тільки явним чином. Операцію [] можна визначати тільки як метод класу.


 

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

3246. Расчеты по поточно-ритмичной технологии производства свинины на промышленном комплексе №125 70.5 KB
  Общая тема: Расчеты по поточно-ритмичной технологии производства свинины на промышленном комплексе №125. Технологические группы свиней. 1.Хряки ( при искусственном осеменении, в том числе пробники) 2.Ремонтные хрячки (со дня покупки из племферм, до...
3247. Сбалансированные системы показателей и эффективность 351 KB
  Лекция 1. Сущность и значение эффективности работы предприятия Лекция 2. Основные принципы формирования эффективной системы хозяйствования предприятия Лекция 3. Системы показателей эффективности А) Модель Дюпон Б) Французская «панель управления»...
3248. Философия: задания и упражнения 2.41 MB
  В пособие включены основные теоретические положения, упражнения и практические задания по курсу "Философия", а также некоторый дополнительный материал, облегчающий пользование пособия Назначение пособия - включить изучающих философию в проблемную си...
3249. Производственный менеджмент. Тексты лекций 586.5 KB
  Введение Современное производство характеризуется постоянно изменяющимися параметрами внешней и внутренней среды, острой необходимостью оперативно применять прогрессивные технологии изготовления продукции, организации и управления предприятием, в ко...
3250. Изучение омических сопротивлений 208 KB
  В настоящей лабораторной работе «Изучение омических сопротивлений» рассматриваются основные законы электрического тока. Вводятся понятия сопротивления, напряжения, разности потенциалов и эдс. Показаны различные способы определения омических...
3251. Анализ эксплуатации локомотивов и работы локомотивных бригад в локомотивном депо 533 KB
  Приведены цели и задачи эксплуатационно-управленческой практики, порядок организации и прохождения практики, права и обязанности студентов во время прохождения практики и требования к отчету по итогам практики. Изложены методика сбора информации и н...
3252. Управление документооборотом на предприятии 197 KB
  Управленческие документы. Состав. Классификация  Общие понятие документационного обеспечения управления Документ – материальный носитель информации, предназначенный для ее обработки и передачи во времени и в пространстве. Понятие д...
3253. Тематическое своеобразие серий публикаций о мировом экономическом кризисе 67.5 KB
  Тематическое своеобразие серий публикаций о мировом экономическом кризисе Кризис - это внутренний механизм насильственного приспособления размеров общественного производства к объему платежеспособного спроса хозяйственных субъектов. Это всеобщее...
3254. Контроль точности при сборке 256.5 KB
  Контроль точности при сборке Осуществляемые в процессе сборки контрольные операции дают возможность установить в соединениях, сборочных единицах и в машине степень соответствия относительного положения и перемещения исполнительных поверхностей техни...