Освобождение памяти, выделенной из размещения новых - PullRequest
2 голосов
/ 27 марта 2012

Рассмотрим следующий код,

#include "iostream"
#include "conio.h"

using namespace std;

class sample
{
      private:
              int i;
      public:
             sample(int ii=0) : i(ii){                         
                   cout<<"Constructing Object"<<endl; 
                   }

             ~sample() { cout<<"Destructing Object"<<endl; }

             void* operator new(size_t nSize, void* loc){
                   cout <<"Inside new"<<endl;
                   cout <<loc<<endl;
                   return loc;
                   }

             void operator delete(void* ptr){
                  cout <<"Inside delete"<<endl;
                  free(ptr);
                  }
};


int main()
{
    int intArr[2];
    sample* samplePtr = new(intArr) sample(5);
    cout <<samplePtr<<endl;

    delete samplePtr;  
//    samplePtr->sample::~sample();
    getch();
}

Выход:

Inside New
0x22ff38
Constructing Object
0x22ff38
Destructing Object
Inside Delete

Здесь я динамически запрашиваю память, которая уже выделена в стеке. Я прочитал, что мне нужно явно вызвать деструктор, как только я закончу. Но когда я пытаюсь вызвать delete для памяти, выделенной в стеке, я получаю вызов деструктора. Означает ли это, что память в стеке освобождается после вызова деструктора?

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

Ответы [ 3 ]

14 голосов
/ 27 марта 2012

Обычный новый оператор делает две вещи:

  1. Вызывает диспетчер динамической памяти, чтобы получить кусок памяти
  2. Конструктор вызовов

Обычный оператор удаления делает обратное

  1. Звонит деструктор
  2. Вызывает диспетчер динамической памяти для освобождения порции памяти

Размещение нового только за один шаг:

  1. Конструктор вызовов

Таким образом, «удаление места размещения» должно выполняться только в один шаг:

  1. Звонит деструктор

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

Эта строка неверна:

delete samplePtr;  // WRONG

Вам нужно сделать "удаление размещения", которое является просто необработанным вызовом дескриптора:

samplePtr->~sample(); // CORRECT
1 голос
/ 27 марта 2012

То, что вы делаете (свободная память с free, которая не была выделена malloc), вызывает неопределенное поведение - может произойти все что угодно. То же самое с delete указателем, который не был получен через new. То же самое с delete указателем, полученным из malloc или наоборот.

То, что это «работает», не означает, что это правильно. Вы не должны free складывать память. Вы правы, что вам нужно вызвать деструктор непосредственно в этом случае.

0 голосов
/ 27 марта 2012

Вот почему размещение нового может быть плохим (на самом деле вы должны избегать его, где это возможно, в этом случае просто выделите объект ), вам не следует delete память (потому что она никогда не создавалась new во-первых, скорее, вам нужно сделать samplePtr->~sample();

...