67312

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

Лекция

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

Розробник може керувати виділенням пам’яті, перевантажуючи оператори new і delete. Такі оператори переважно перевантажуються як методи класу. Проте дозволено перевантаження і як дружніх функцій Операторні функції операторів new і delete в обидвох випадках мають вид...

Украинкский

2014-09-07

201.5 KB

1 чел.

Лекція № 14

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

План

  1.  Перевантаження операторів new і delete
  2.  Перевантаження операторів new тa delete як методів  класу
  3.  Перевантаження операторів new тa delete як дружніх функцій
  4.  Перевантаження операторів new і delete при роботі з масивами
  5.  Оператор new із розміщенням

  1.  Перевантаження операторів new і delete

  •  Розробник може керувати виділенням пам’яті, перевантажуючи оператори new і delete. Такі оператори переважно перевантажуються як методи класу. Проте дозволено перевантаження і як дружніх функцій
  •  Операторні функції операторів new і delete в обидвох випадках мають вид
  1.  void* operator new (size_t size);
  2.  void operator delete (void*);
  •  Операторна функція new виділяє size байт і повертає адрес виділеної пам’яті. Конструктори та деструктори об’єктів при цьому викликаються автоматично.
  •  Тип size_t є псевдоіменем цілочисельного типу.

  1.  Перевантаження операторів new тa delete як методів  класу

  •  Перш за все відзначимо два дуже важливих моменти для перевантажених як методи класу операторів new і delete (а також іх різновидів):
  •  такі оператори вважається статичними, навіть без явного оголошення. При цьому вони не отримують вказівника this;
  •  такі оператори будуть використовуватись при створення динамічних змінних лише для копій даного класу. При цьому для виділення пам’яті під змінні інших типів не будуть заміщуватись стандартні оператори.
  •  Розглянемо програму, в якій оператор new реалізовує виділення пам’яті через функцію malloc(). Як відомо одночасне використання механізмів розподілу та звільнення пам’яті, які передбачені в мовах С та С++, тобто використання пар new - free() та malloc() - delete , може привести до непередбачуваних результатів. А тому наведена програма несе певний зміст, який полягає в узгодженні різних механізмів виділення пам’яті.

  1.  Перевантаження операторів new тa delete як дружніх функцій

  •  Оператори new  і delete  можуть перевантажуватись як дружні функціі. При цьому перевантажуються вбудовані оператори.  Це означає, що при виділення пам’яті під змінні іншого (відмінного від даного класу) також буде викликатись перевантажений оператор new  чи delete.
  •  Треба пам’ятати, що синтаксично оператор new повинен приймати лише один параметр типу size_t

  1.  Перевантаження операторів new і delete при роботі з масивами

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

#include <iostream>

class A

{

public:

int i;

A() {  i = 0; mes();}

A(int i) {  this->i = i; mes();}

void mes(){ std::cout <<" Constructor A" <<endl;}

~A() {  std::cout<<" Destructor A"<< endl;}

friend void* operator new (size_t t,int x,int y);

friend void* operator new (size_t t);

friend void* operator new [] (size_t t);

friend void operator delete[](void*);

friend void operator delete(void*);

};

void* operator new (size_t t, int x, int y)  //N1

{

std::cout<<"Operator new (size_t t, int x,int y)"<<endl;   return malloc(x*y);

}

void* operator new (size_t t)   //N2

{

std::cout<<"Operator new (size_t t)" << endl;

return malloc(t);

}

void* operator new [] (size_t t)   //N3

{

std::cout<<"Operator new [] (size_t t)"<<endl;

return malloc(t);

}

void operator delete (void* p)   //D1

{

std::cout <<"Operator delete (void* p)"<<endl;

free(p);

}

void operator delete [] (void* p)  //D2

{

std::cout <<"Operator delete [] (void* p)"<<endl;

free(p);

}

void main()

{

char mem [sizeof(A)];

void *p = mem;

A * a  = new(p) A(1);  // оператор N2

std::cout<<"a->i="<<a->i<<endl;

delete a;    // оператор D1

std::cout<<"----------------------"<<endl;

A * a2  = new(10,10) A(2); // оператор N1

std::cout<<"a2->i="<<a2->i<<endl;

delete a2;    // оператор D1

std::cout<<"----------------------"<<endl;

A * a3  = new A[5];  // оператор N3

std::cout<<"a3->i="<<a3->i<<endl;

delete [] a3;   // оператор D2

std::cout<<"----------------------"<<endl;

int * p2  = new int[6];  // оператор N3

std::cout<<"Massive is created"<<endl;

delete [] p2;   // оператор D2

}

  1.  Оператор new із розміщенням

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

В цьому випадку треба явно викликати деструктор класу

    Оскільки new і delete – оператори, то їх також можна перевизначати. . Це доводиться робити, якщо виникає необхідність створити особливий механізм розподілу пам'яті. Наприклад, можна створити процедуру виділення області пам'яті, яка, якщо область множини виявиться вичерпаною, автоматично починає використовувати дисковий файл як віртуальну пам'ять. У будь-якому випадку реалізація перевантаження цих операторів є не складнішою за перевантаження будь-яких інших.

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

// Виділення області пам'яті для об'єкта

void *operator new(size_t size)

{

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

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

return pointer_to_memory;

}

// Видалення об'єкта.

void operator delete(void *p)

{

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

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

}

void * - покажчик на область пам'яті, виділювану під об'єкт, size - розмір об'єкта в

байтах, size_t - тип розмірності області пам'яті, int чи long.

   Тип size_t спеціально визначено, щоб забезпечити зберігання розміру максимально можливої області пам'яті, яку можна виділити для об'єкта. Параметр 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 *p)

{

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

При цьому автоматично викликається деструктор для

кожного елемента масиву. */

}

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

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

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

Приклад. Демонстрація механізму перевантаження операторів new і delete

#include <iostream>             // Для потокового введення-виведення

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

#include <cstdlib>             // Для використання бібліотечних функцій

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

class kooClass

{

int x, y, z;             // Тривимірні координати

    public:

kooClass() { x = y = z = 0; cout << "Створення об'єкта 0, 0, 0" << endl; }

kooClass(int c, int d, int f)    {  x = c; y = d; z = f;

                                                 cout << "Створення об'єкта " << c << ", ";

                                                 cout << d << ", " << f << endl; }

~kooClass()     { 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)

{      void *p;

      cout << "Виділення області пам'яті для об'єкта класу kooClass" << endl;

      p = malloc(size);

             // Генерування винятку у разі невдалого виділення області пам'яті.

      if(!p)

         {    bad_alloc ba;

              throw ba;

         }

      return p;

}

    // Перевантаження оператора new для масиву об'єктів типу kooClass.

void *kooClass::operator new[](size_t size)

{     void *p;

     cout << "Виділення області пам'яті для масиву kooClass-oб'єктів" << endl;

          // Генерування винятку при невдачі.

     p = malloc(size);

     if(!p)

        { bad_allос ba;

         throw ba;

        }

    return p;

}

    // Перевантаження оператора delete для класу kooClass.

void kooClass::operator delete(void *p)

{        cout << "Видалення об'єкта класу kooClass" << endl;

        free(p);

}

   // Перевантаження оператора delete для масиву об'єктів типу kooClass.

void kooClass::operator delete[](void *p)

{       cout << "Видалення масиву об'єктів типу kooClass" << endl;

       free(p);

}

    // Відображення тривимірних координат x, y, z.

void kooClass::showB(char *s)

{      cout << "Координати об'єкта <" << s << ">: ";

      cout << "x= " << x << ", y= " << y << ", z= " << z << endl;

}

int main()

{     kooClass *p1, *p2;

     try

       {   p1 = new kooClass[3];                  // Виділення області пам'яті для масиву

           р2 = new kooClass(5, 6, 7);          // Виділення області пам'яті для об'єкта

       }

    catch(bad_alloc ba)

       {   cout << "Помилка під час виділення області пам'яті" << endl;

            return 1;

       }

    p1[1].showB("Базовий клас: ");

    p2->showB("Базовий клас: ");

    delete [] p1;          // Видалення масиву

    delete p2;             // Видалення об'єкта

    getch(); return 0;

}

   Внаслідок виконання ця програма відображає на екрані такі результати:

Виділення області пам'яті для масиву kooClass-oб'єктів.

Створення об'єкта 0, 0, 0

Створення об'єкта 0, 0, 0

Створення об'єкта 0, 0, 0

Виділення області пам'яті для об'єкта класу kooClass.

Створення об'єкта 5, 6, 7

0, 0, 0

5, 6, 7

Руйнування об'єкта

Руйнування об'єкта

Руйнування об'єкта

Видалення масиву об'єктів типу kooClass.

Руйнування об'єкта

Видалення об'єкта класу kooClass.

    Перші три повідомлення Створення об'єкта 0, 0, 0 видані конструктором класу kooClass (який не має параметрів) під час виділення області пам'яті для триелементного масиву. Як уже зазначалося вище, під час виділення області пам'яті для масиву автоматично викликається конструктор кожного елемента. Повідомлення Створення об'єкта 5, 6, 7 видано конструктором класу kooClass (який приймає три аргументи) під час виділення області пам'яті для одного об'єкта. Перші три повідомлення Руйнування об'єкта видані деструктором внаслідок видалення триелементного масиву, оскільки при цьому автоматично викликався деструктор кожного елемента масиву. Останнє повідомлення Руйнування об'єкта видане під час видалення одного об'єкта класу kooClass. Важливо розуміти, що, коли оператори new і delete перевизначені для конкретного класу, то внаслідок їх використання для даних інших типів будуть задіяні оригінальні версії операторів new і delete. Це означає, що при додаванні у функцію main() наступного рядка буде виконано стандартну версію оператора new:

int *f = new int; // Використовується стандартна версія оператора new.


 

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

1938. Стадии развития воспитательного коллектива. Средства формирования коллектива. Стили педагогического управления детским коллективом 22.28 KB
  Коллектив как специально организованное объединение учащихся. Процесс формирования коллектива. Стили управления детским коллективом.
1939. НОВЫЕ ПОДХОДЫ К СИНТЕЗУ ФОТОХРОМНЫХ ДИГЕТАРИЛЭТЕНОВ 1.19 MB
  Получение диарил(гетарил)ацетиленов из терминальных ацетиленов. Присоединение комплексов переходных металлов к диарилацетиленам. Попытки проведения внутримолекулярной конденсации 2,2,4,4-тетраметил-2,4-бис(2,5-диметил-3-тиенил)-3-тиапентан-1,5-диона. Синтез дитиенилэтенов с помощью внутри- и межмолекулярных конденсаций карбонильных соединений ряда тиофена по мак-мурри.
1940. Анекдот как средство переживания национальной идентичности (на материале анализа еврейских анекдотов) 1.17 MB
  Анализ теоретических и эмпирических подходов к исследованию идентичности. Изучение особенностей еврейской этнической идентичности. Социально-психологические аспекты проблемы комического. Еврейский анекдот как материал изучения еврейской национальной идентичности. Различные подходы к анализу текстов. Классификация и количественный анализ еврейских анекдотов
1941. Концепт Труд как объект идеологизации 1.17 MB
  Семантическое ядро концепта труд в русском языке, лексическое значение и концепт в научно-лингвистической интерпретации. Семантическая структура слов труд, работа. Витки идеологизации концепта труд в газете Магнитогорский рабочий.
1942. Функциональное состояние сердечно-сосудистой системы организма детей с учетом их конституциональных особенностей 1.17 MB
  Морфофункциональные особенности здоровых детей в норме и при врожденной патологии сердечно-сосудистой системы. Конституциональный подход в фундаментальной биологической характеристике целостного организма. Клиническая характеристика врожденной сердечно-сосудистой патологии. Возрастные и конституциональные особенности функционирования сердечно-сосудистой системы организма детей.
1943. Только трудом велик человек 25.02 KB
  Воспитание трудолюбия, творческого отношения к учению, труду, жизни. Ценности: уважение к труду, творчество и созидание, стремление к познанию и истине, целеустремлённость и настойчивость, бережливость, трудолюбие.
1944. Воспитательный процесс в школе 24.85 KB
  Организационно-педагогические мероприятия. Воспитание положительного отношения школьников к учению. Воспитание нравственных ценностей у школьников. Физическая культура и здоровье учащихся. Работа с родителями и общественностью.
1945. Добро починається з тебе 24.1 KB
  Мета: допомогти учням з’ясувати сутність понять добро, доброта, милосердя як принципів людського буття, навчити учнів критично ставитися до своїх вчинків та вчинків інших людей, аналізувати матеріал з різних джерел і самостійно робити правильні висновки.
1946. Воспитательные функции классного руководителя как организатора воспитательного процесса в школе 25.53 KB
  Основным структурным элементом воспитательной системы школы является класс. Именно здесь организуется познавательная деятельность, формируются социальные отношения между учащимися. Представительские функции в органах самоуправления школы реализуются также чаще всего от имени класса.