new (C++)

У мові програмування C++, так само як і в багатьох подібних до C++ мовах, new це конструкція мови, яка дозволяє динамічно під час виконання програми виділяти пам'ять із купи і задати початкові значення за допомогою конструктора. [1] На відміну від іншої форми - "виразу new", new намагається виділити достатньо пам'яті із вільної області пам'яті для нового об'єкту. Якщо операція відбулась успішно, вона ініціалізує пам'ять і повертає адресу нововиділеної області пам'яті.[2][3] В той же час, якщо new не може виділити пам'ять у вільній області буде згенерована виключна ситуація типу std::bad_alloc. Це позбавляє необхідності безпосередньо перевіряти результат процедури виділення пам'яті. Пам'ять, виділена за допомогою оператора new, може бути звільнена за допомогою виклику delete, який викликає деструктор об'єкту. Щоб не допустити витоків пам'яті delete має викликатися для всіх об'єктів, які були створені за допомогою оператора new.

Синтаксис

Оператор new має наступний синтаксис:

type_name * p_var = new type_name;

де “p_var” це об’явлений вказівник на тип “type_name” безпосередньо в даній строчці коду, або iможливо десь у коді раніше. “type_name” може бути базовим типом даних чи тип об'єкту об’явлений програмістом (enum, class, або struct). Якщо “type_name” є типом класу, для створеного об'єкту буде викликано конструктор за замовченням. Для того, щоб ініціалізувати значення нової змінної, існує наступна форма оператора new:

p_var = new type(initializer);

де “initializer” є початковим значенням, яке буде назначено новій змінній, або якщо  “type” це тип класу, “initializer” це аргумент(и) конструктору. За допомогою new також можна виділити пам'ять під масив:

p_var = new type [size];

В такому випадку, “size” вказує довжину створюваного одномірного масиву. У вигляді значення змінної “p_var”, оператор поверне адресу першого елементу масиву, тому

p_var[n]

дозволить отримати значення n-го елементу масиву (починаючи з 0). Пам’ять виділена за допомогою new має бути звільнена за допомогою оператора delete для того, щоб не допустити витоків пам’яті. Масиви, які створюються за допомогою new[], завжди мають бути звільнені за допомогою оператору delete[].

int *p_scalar = new int(5); //виділяє пам’ять під змінну типу integer, і задає їй значення 5. (такий самий синтаксис у випадку визову конструктора)

int *p_array = new int[5];  // виділяє пам’ять під массив з 5-ти послідовних цілих чисел. (значення залишаються не визначеними)
int *cpp11_array = new int[5] {1, 2, 3, 4, 5};  //виділяє пам’ять під масив з 5-ти послідовних цілих чисел і ініціалізує їх значеннями {1, 2, 3, 4, 5}. (лише в C++11)

У версії C++98 не можливо написати ініціалізатор для масивів створених за допомогою new. Якщо списку ініціалізації немає, всі елементи масиву будуть проініціалізовані конструктором за замовченням для даного типу. Якщо для типу не існує конструктора за замовченням, це призведе до помилки компіляції.

Реалізація

В компіляторах, які слідують стандарту ISO C++, у випадку коли система не може виділити достатньо пам’яті, буде викликана функція new_handler (якщо така зареєстрована), доки запитувана пам’ять не зможе бути виділена. Якщо функція new_handler також не може повернути достатньо пам’яті, або вона не назначена, буде згенерована виключна ситуація типу std::bad_alloc. Програмі не потрібно перервіряти значення повернутого вказівника, якщо не відбулося виключної ситуації, то виділення пам’яті завершилося вдало. Реалізація операцій визначена в файли заголовку <new>. В більшості реалізацій C++ оператор new також можна перевизначити, для того щоб визначити його нову поведінку.[1]

Вивільнення динамічно виділеної пам’яті

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

int *p_var = new int;
delete p_var;
p_var = nullptr;
 
int *p_array = new int[50];
delete[] p_array; 
p_array = nullptr;

Слід відзначити, що компілятор не забов’язаний видавати попередження при використанні не відповідного оператору delete. Крім того, використання невідповідного деалокатору може призвести до непередбачуваної поведінки.

Зміна величини виділеної пам’яті, яка була виділена за допомогою new[]

На відміну від аналогічного методу мови С - realloc, не можливо безпосередньо змінити величину виділеної пам’яті, яка була виділена за допомогою new[]. Для того, щоб збільшити або зменьшити розмір блоку, необхідно створити новий блок необхідного розміру, скопіювати туди значення із існуючого блоку пам’яті, і видалити старий блок. В стандартній бібліотеці C++ запропонована реалізація динамічного масиву, який може змінювати свій розмір – це шаблонний клас std::vector.

Перевизначення оператора new

Конструкція мови С++, яка тільки виконує операцію виділення пам’яті задається у вигляді наступного оператора:

void* operator new(size_t size)

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

Розміщення об’єкта в уже виділеній пам’яті

Існує конструкція, яка дозволяє за допомогою оператора new() розмістити об’єкт в уже виділеній пам’яті :

char *buffer = new char[sizeof(ClassName)];  // виділяємо пам’ять під об’єкт
if( buffer != NULL)
{
    ClassName *cl_p = new (buffer) ClassName();  // розміщаємо в виділеному буфері об’єкт 

    /* використовуємо новостворений об'єкт */

    cl_p->~ClassName();     // явно викликаємо деструктор об’єкту
}    


delete [] buffer;       // вивільняємо виділену раніше пам’ять

Таким методом можна почергово використовувати один регіон пам’яті для різних об’єктів, не використовуючи, затратну по часу, операцію виділення пам’яті для кожного з них.

Примітки

  1. Savitch, Walter (2013). Absolute C++. Pearson. с. 420–445. ISBN 0132846810.
  2. IBM Documentation describing C++'s operator new. Процитовано 6 листопада 2013.
  3. Microsoft Visual Studio operator new documentation. Процитовано 6 листопада 2013.

Див. також

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.