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.


 

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

30743. Холодная война и ее этапы (с 40-х по 90-е гг.) 24.5 KB
  Конфликт двух сверх держав США и СССР противостояние двух военнополиитческих блоков НАТО и Варшавского договора. Воплощением конфликта стала холодная война между США и СССР. Начало Холодной войны было в момент послевоенного урегулирования когда возникли противоречия между союзниками антигитлеровской коалиции США и Великобритании и СССР. был создан англоамериканский военный союз для борьбы с СССР и коммунистической угрозой.
30744. Захватнические планы Гитлеровской Германии и их осуществление (1935 – 1941 гг.) 24 KB
  Захват чужих территорий стал центром всей политики гитлеровской Германии. Немаловажное значение для развития экономического потенциала Германии и использования его в военных целях против СССР имели захват и ограбление Австрии Чехословакии Польши Франции и других европейских стран. На выполнение только военных заказов Германии работали предприятия оккупированных западноевропейских стран.
30745. Возникновение и приход к власти фашизма в Италии и Германии: общее и особенное 24 KB
  Так в 1919 г возникла 1 фашистская организация в Италии а в Германии националсоциальнеческая. В Италии её возглавил Муссолини а в Германии Гитлер фюрер. фашистское движение в Италии было преобразовано в национальную фашистскую партию с 1922 г.
30746. США и Латинская Америкак: эволюция и проблемы взаимоотношений во второй половине 20 столетия 26.5 KB
  Во время Второй мировой войны создались благоприятные условия для развития национального капитала в Латинской Америке. Выросли цены на сырье ослабло влияние национального капитала увеличились средства для вложения в национальную промышленность. Новый уровень глобализации иначе говоря огромная роль мировых хозяйственных связей привлечение современной технологии и иностранного капитала стал частью стратегии латиноамериканских стран. Основным источником накопления капиталов и модернизации стали широкое привлечение иностранного...
30747. Причины зарождения и сущность фашизма 24 KB
  в конкретной исторической обстановке фашизм нужен определенным кругам империализма чтобы справиться с возрастанием революционного движения разрешить в свою пользу классовые противоречия которые нельзя разрешить старыми методами и формами борьбы. Мировому капиталу фашизм был нужен чтобы разрушить главной оплот международного революционного процесса и антиимпериалистической борьбы СССР. Германский фашизм сопровождался политическими убийствами погромами и др.
30748. Латинская Америка: что принесли неолиберальные преобразования (на опыте 1980 - 1990-х гг.) 27 KB
  стимулировал экономический рост Латинской Америки в начале 90х гг. Другая болевая точка современной Латинской Америки безработица принявшая беспрецедентные масштабы. Финансовоэкономическая стратегия Латинской Америки на 90е гг. В задачи консенсуса входило преодоление инфляции сокращение бюджетного дефицита укрепление национальных валют Латинской Америки.
30749. Причины и характер первой мировой войны, цели воюющих сторон. (28 июля 1914 — 11 ноября 1918) 23.5 KB
  28 июля 1914 11 ноября 1918 стремление к переделу мира в результате противостояния двух военных блоков: Тройственного Союза Германия АвстроВенгрия Италия и Антанты Англия Франция Россия борющихся за гегемонию на континенте. слабое рабочее движение в результате в ряде стран победили партии войны в правящих кругах ряда Западных стран Германия Великобритания АвстроВенгрия и Франция. Цели: Германия создать Новую Европу где влияния Англии Франции и России свелись бы к нулю. АвстроВенгрия как и Германия за...
30750. Бетонирование колонн, стен, перекрытий 14.54 KB
  При возведении стен в разборнопереставной опалубке смесь укладывают участками высотой не более 3 м. В стены толщиной более 05 м при слабом армировании подают бетонную смесь подвижностью 4. Бетонную смесь подают непосредственно в опалубку в нескольких точках по длине участка бадьями виброжелобами бетононасосами. При высоте стен более 3 м используют звеньевые хоботы при этом смесь укладывают горизонтальными слоями толщиной 03.
30751. Назначение и виды опалубок. Требования к опалубке. Оборачиваемость опалубных форм 16.57 KB
  Поверхность опалубки непосредственно примыкающая к бетону должна быть плотной иметь малую с бетоном адгезию и не иметь щелей чтобы не вытекало цементное молоко. Важнейшим показателем качества опалубки является ее оборачиваемость т. Применение инвентарной многооборачиваемой опалубки из унифицированных элементов с модульным изменением размеров и укрупненных блоков способствует снижению трудоемкости и стоимости опалубочных работ. Для изготовления опалубки используют доски из древесины II III и IV сортов хвойных пород допускается...