Хорошее понимание того, как динамическая память действительно работает на C ++, имеет важное значение для того, чтобы стать хорошим программистом на C ++. Память в вашей программе на C ++ делится на две части -

  • Стек. Все переменные, объявленные внутри функции, будут занимать память из стека.
  • Куча - это неиспользуемая память программы и может использоваться для динамического распределения памяти при запуске программы.

Много раз вы заранее не знаете, сколько памяти вам потребуется для хранения определенной информации в определенной переменной, а размер требуемой памяти можно определить во время выполнения.

Вы можете выделить память во время выполнения в куче для переменной данного типа с помощью специального оператора в C ++, который возвращает адрес выделенного пространства. Этот оператор называется оператором new.

Если вам больше не нужна динамически распределенная память, вы можете использовать оператор delete , который отменяет выделение памяти, которая ранее была назначена новым оператором.

Операторы new и delete

Существует следующий общий синтаксис для использования оператора new для динамического распределения памяти для любого типа данных.

new data-type;

Здесь data-type может быть любым встроенным типом данных, включая массив или любые пользовательские типы данных, которые включают класс или структуру. Начнем со встроенных типов данных. Например, мы можем определить указатель на тип double, а затем запросить выделение памяти во время выполнения. Мы можем сделать это, используя new оператор со следующими утверждениями:

double* pvalue  = NULL; // Pointer initialized with null
pvalue  = new double;   // Request memory for the variable

Возможно, память не была выделена успешно, если бы бесплатный магазин был израсходован. Поэтому рекомендуется проверить, возвращает ли новый оператор указатель NULL и предпринять соответствующие действия, как показано ниже:

double* pvalue  = NULL;
if( !(pvalue  = new double )) {
   cout << "Error: out of memory." <<endl;
   exit(1);
}

Функция malloc() из C все еще существует в C ++, но рекомендуется избегать использования функции malloc(). Основным преимуществом new over malloc () является то, что новый не просто выделяет память, но и строит объекты, которые являются главной целью C ++.

В любой момент, когда вы чувствуете, что переменная, которая была динамически распределена, больше не требуется, вы можете освободить память, которую он занимает в свободном хранилище, с оператором delete следующим образом -

delete pvalue;        // Release memory pointed to by pvalue

Поставим выше понятия и сформируем следующий пример, чтобы показать, как работают new и delete:

#include <iostream>
using namespace std;

int main () {
   double* pvalue  = NULL; // Pointer initialized with null
   pvalue  = new double;   // Request memory for the variable
 
   *pvalue = 29494.99;     // Store value at allocated address
   cout << "Value of pvalue : " << *pvalue << endl;

   delete pvalue;         // free up the memory.

   return 0;
}

Если мы скомпилируем и запустим код выше, это приведет к следующему результату -

Value of pvalue : 29495

Динамическое распределение памяти для массивов

Предположим, вы хотите выделить память для массива символов, т. е. Строку из 20 символов. Используя тот же синтаксис, который мы использовали выше, мы можем динамически распределять память, как показано ниже.

char* pvalue  = NULL;         // Pointer initialized with null
pvalue  = new char[20];       // Request memory for the variable

Чтобы удалить массив, который мы только что создали, будет выглядеть так:

delete [] pvalue;             // Delete array pointed to by pvalue

Следуя аналогичному обобщенному синтаксису нового оператора, вы можете выделить многомерный массив следующим образом:

double** pvalue  = NULL;      // Pointer initialized with null 
pvalue  = new double [3][4];  // Allocate memory for a 3x4 array 

Однако синтаксис для выпуска памяти для многомерного массива будет по-прежнему оставаться таким же, как и выше:

delete [] pvalue;            // Delete array pointed to by pvalue

Динамическое распределение памяти для объектов

Объекты не отличаются от простых типов данных. Например, рассмотрим следующий код, в котором мы собираемся использовать массив объектов, чтобы прояснить концепцию -

#include <iostream>
using namespace std;

class Box {
   public:
      Box() { 
         cout << "Constructor called!" <<endl; 
      }
      ~Box() { 
         cout << "Destructor called!" <<endl; 
      }
};
int main() {
   Box* myBoxArray = new Box[4];
   delete [] myBoxArray; // Delete array

   return 0;
}

Если вы выделили массив из четырех объектов Box, конструктор Simple будет вызываться четыре раза и аналогично при удалении этих объектов, деструктор также будет называться столько же раз.

Если мы скомпилируем и запустим код выше, это приведет к следующему результату:

Constructor called!
Constructor called!
Constructor called!
Constructor called!
Destructor called!
Destructor called!
Destructor called!
Destructor called!