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.


 

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

7791. Педагогические Взгляды французских материалистов XVIII века 33 KB
  Педагогические Взгляды французских материалистов XVIII века Педагогические идеи Клода Адриана Гельвеция Гельвеций прославился как автор книги Об уме, которая вышла в 1758 г. и вызвала яростные нападки со стороны всех сил реакции, правя...
7792. Педагогическая технология Руссо 31.5 KB
  Педагогическая технология Руссо Основу педагогических взглядов Руссо составляет теория естественного воспитания, которая тесно связана с его социальными взглядами, с его учением о естественном праве Руссо утверждал, что человек родится совершенным, ...
7793. Педагогическая деятельность и теория Яна Амоса Коменского 36 KB
  Педагогическая деятельность и теория Яна Амоса Коменского О роли воспитания, его целях и задачах Взгляды Коменского на ребенка, его развитие и воспитание коренным образом отличались от средневековых представлений. Вслед за гуманистами эпохи Возрожде...
7794. Педагогическая мысль и школа в период Французской буржуазной революции XVIII века 43 KB
  Педагогическая мысль и школа в период Французской буржуазной революции XVIII века В 70-х годах XVIII века во Франции создалась революционная ситуация. В недрах феодального общества выросли и созрели формы нового, капиталистического уклада. О...
7795. Педагогическая мысль эпохи Возрождения 37.5 KB
  Педагогическая мысль эпохи Возрождения Наиболее ярко педагогическая мысль эпохи Возрождения представлена трудами итальянских, немецких и французских ученых-гуманистов. Среди итальянских гуманистов эпохи Возрождения особенно выделяется Витторино да Ф...
7796. Педагогическое сознание Гербарта (цели, средства) 43 KB
  Педагогическое сознание Гербарта (цели, средства) Педагогическое сознание Гербарта впитало и переработало многие передовые идеи той эпохи французских мыслителей 18 века, немецкой классической философии, филантропистов, Песталоцци, что и позволило ем...
7797. Послереформенные изменения в России (вторая половина 19 века) 27.5 KB
  Послереформенные изменения в России (вторая половина 19 века) Новые условия хозяйственной и общественной жизни пореформенной России настоятельно требовали подготовлённых и грамотных людей. Необходимо было значительно расширить базу народного образов...
7798. Просвещение абсолютизма 41 KB
  Просвещение абсолютизма Просвещённый абсолютизм - политика, проводимая во второй половине XVIII века рядом монархических стран Европы и направленная на устранение остатков средневекового строя в пользу капиталистических отношений. Основы просве...
7799. Развитие системы образования в России в начале 20 века 32 KB
  Развитие системы образования в России в начале 20 века Основным типом школы в России к началу ХХ века, как и раньше, была начальная школа, отличавшаяся пестротой не только по ведомственной принадлежности, но и по срокам и содержанию обучения. Самыми...