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


 

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

41825. Работа с данными в программе Microsoft Excel 277 KB
  Цель данной лабораторной работы - научиться создавать с помощью пакета Excel тип рабочей таблицы, соответствующий базе данных. А также научиться работать с данными таблицы Excel как с базой данных.
41826. Решение задачи аппроксимации исходных данных 47 KB
  В окне Algebra1 решаем исходное уравнение ( команда Solve→Expression), выбираем численные значение корней (Numerically) и, указывая ОИК, находим равенство: Проверить найденные значения корней.
41827. Система питания двигателя Зил-138 от газаоболонной установки 218.85 KB
  В цилиндрическом корпусе 24 редуктора размещены камера А первой ступени камера Б второй ступени и кольцеобразная камера В вакуумного разгружателя.Одна из стенок камеры первой ступени образована резиновой диафрагмой 5 края которой зажаты между корпусом редуктора и крышкой 4.В камере второй ступени находится зажатая по окружности между верхней частью корпуса и крышкой 36 диафрагма 37. Ее центральная часть соединена рычагом 29 с клапаном 9 второй ступени.
41828. Проведение исследования на основе готовой компьютерной модели 163.07 KB
  LINE х1 у1х2 у2 cоператор изображающий отрезок прямой х1 у1 начало отрезка х2 y2 конец отрезка c номер цвета. LINE х1 у1х2 у2 c B оператор изображающий прямоугольник со сторонами параллельными осями координат. LINE х1 у1х2 у2 c BF оператор изображающий закрашенный прямоугольник c номер цвета.146 6 Перемещение начала координат в центр экрана LINE 3.
41829. Работа с запросами в MS Access 117.5 KB
  Порядок выполнения задания Создание запросавыборки Создать запрос содержащий поля: Идент.Для этого необходимо выполнить следующую последовательность действий: При выбранной вкладке Запросы выполнить щелчок по кнопке . Открывается окно Новый запрос в котором выбрать режим создания запроса Конструктор затем ; Открывается окно Запрос1: запрос на выборку а затем активизируется окно Добавление таблицы в котором выбрать из списка таблиц таблицу Сотрудник щелчком мыши по имени таблицы а затем выполнить щелчок по кнопке после чего...
41830. Создание и форматирование таблиц. Использование логических и математических функций в табличных вычислениях 178.5 KB
  Использование логических функций необходимо, когда для выбора правильного решения нужно проверить выполнение одного или нескольких условий. Наиболее часто используемые функции этой категории
41831. Создание архива данных. Извлечение данных из архива. Атрибуты файла и его объем 27.83 KB
  Атрибуты файла и его объем Цель: изучение принципов архивации файлов функций и режимов работы наиболее распространенных архиваторов приобретение практических навыков работы по созданию архивных файлов и извлечению файлов из архивов. Теоретические сведения к лабораторной работе Архивация упаковка помещение загрузка исходных файлов в архивный файл в сжатом или несжатом виде. Архивация предназначена для создания резервных копий используемых файлов на случай потери или порчи по какимлибо причинам основной копии невнимательность...
41832. Художественные средства. Инструмент rtistic Mediа 217.5 KB
  Примеры рисования инструментом rtistic Medi Художественные средства Инструмент rtistic Medi Художественные средства входит в состав группы инструментов Curve Кривая рис. Инструмент rtistic Medi Художественные средства включает в себя пять отличных друг от друга режимов работы. Инструмент rtistic Medi Художественные средства может работать в следующих режимах: Preset Заготовка заготовка для живописи; Brush Кисть художественная кисть; Spryer Распылитель распылитель; Clligrphic Каллиграфический ...
41833. ИССЛЕДОВАНИЕ ТИПОВОЙ СХЕМЫ УПРАВЛЕНИЯ ЭЛЕКТРОПРИВОДОМ ПОСТОЯННОГО ТОКА ПОДЪЁМНО КРАНОВОГО МЕХАНИЗМА 247 KB
  Изучить принцип действия и исследовать работу одной из типовых схем управления электроприводом подъёмно кранового механизма с ДПТ независимого возбуждения. Ознакомиться с электрооборудованием типового шкафа управления. Исследовать работу схемы управления электроприводом подъёмно кранового механизма.