Различия между свободным в C и delete в C ++? - PullRequest
4 голосов
/ 25 июля 2011

Я знаю, что свободная операция в C заключается в сообщении компилятору, что этот конкретный блок памяти свободен для использования компилятором для дальнейшего выделения, но память не освобождается.

удаление в C ++?так же, как бесплатно?

Ответы [ 4 ]

19 голосов
/ 25 июля 2011

В C ++ существует два понятия delete: первое - это оператор , объявленный как ::operator delete(void*), который в основном только освобождает память и обычно не рассматривается большинством программистов.Другим является выражение для удаления , delete p;, где p - это T*.Выражение вызывает деструктор объекта, на который указывает p (и затем освобождает память), что является важной языковой особенностью C ++, которая не имеет аналога в C.

Как правило, выпара new выражений с delete выражениями и malloc() вызовами функций с free() вызовами функций:

T * p = new T;        // constructor called!
delete p;             // destructor called!

void * x = malloc(5); // just raw memory
free(x);              // freed

Расширенная часть (не в ответ на вопрос ОП)

Время жизни динамического объекта в C ++ соответствует следующей общей схеме: выделять, конструировать, уничтожать, освобождать.Стандартное выражение new выполняет выделение и построение, а стандартное выражение delete выполняет уничтожение и освобождение.

Вы можете записать процесс вручную:

T * p = (T*)::operator new(sizeof(T));   // allocate raw memory
p = new (p) T;                           // call the constructor ("placement new")

/*...*/

p->~T();                                 // destroy the object
::operator delete(p);                    // deallocate the memory

Фактически, есливы действительно хотели реализовать Baby C ++, вы могли бы определить операторы так же, как malloc / free:

void * operator new(size_t n) { return malloc(n); }
void   operator delete(void * p) { free(p); }

Настоящая магия C ++ происходит благодаря new и delete выражения : стандартное выражение new вызывает конструктор (выражение new является способом only для вызова конструктора в C ++!) После выделения,в то время как стандартное выражение удаления вызывает деструктор перед освобождением.

Почему «стандартное выражение»?Ну, вы также можете определить и перегрузить многие другие версии операторов new и delete.Тем не менее, есть важная асимметрия: хотя вы можете использовать пользовательский оператор new в пользовательском выражении new (обычно называемом «размещение нового»), эквивалентного выражения «размещение-удаление» не существует.Поэтому всякий раз, когда вы используете пользовательское выражение new, вы должны вручную вызывать деструктор перед вызовом соответствующего пользовательского оператора удаления :

T * p = new (A, B, C) T;                          // some custom new expression

// Entirely equivalent version:

T * p = (T*) ::operator new(sizeof(T), A, B, C);  // this is your custom overload
T * p = new (p) T;                                // std. placement-new expression calls constructor

/* ---- later ---- */

p->~T();                                          // Must destroy manually!
::operator delete(p, A, B, C);                    // your matching custom overload

Обратите внимание, что пользовательского удаления не существуетвыражение delete (A,B,C) p'!

Для полноты, оператор стандартного размещения стандарта *1062*, единственной целью которого является вызов конструктора, в соответствии со стандартом должен принять следующую форму:

void * operator new(size_t, void * p) { return p; }

Это соответствует delete Оператор также обязателен, имя ничего не делать:

void operator delete(void * p, void *) { }

Вы можете увидеть в приведенном выше общем примере, почему это необходимо.

Важно всегда перегружать пользовательские версии new и delete парами!Причина в том, что если конструктор объекта завершается неудачно с исключением внутри конструктора, то память освобождается при вызове оператора delete, который соответствует некорректному выражению new.


Второе обновление: Чтобы быть безопасным от исключений, мы должны учитывать, что конструктор T может выдать:

Версия 1:

try {
  T * p = new (A, B, C) T;
  /* ... */
  p->~T();
  ::operator delete(p, A, B, C); // automatically invoked if T::T() throws!
}
catch(...) { }

Версия 2:

void * addr = ::operator new(sizeof(T), A, B, C);
try {
  T * p = new (addr) T;  // might throw
  /* ... */
  p->~T();
  // ::operator delete(p, addr); // ditto as in (1), but does nothing
}
catch(...) { }
::operator delete(addr, A, B, C);
2 голосов
/ 25 июля 2011

delete - это то же самое (ish), что и free, но имеет важные различия.Наиболее заметное отличие состоит в том, что delete будет запускать деструктор объектов, тогда как free не будет.

Как отмечается в комментариях, еще одна очень важная деталь - это не смешивание malloc / free и new / delete.Если вы используете malloc, используйте free и аналогично, если вы используете new, используйте delete!

0 голосов
/ 25 июля 2011

malloc () и free () не должны использоваться в коде C ++, потому что они не поддерживают семантику объектов. Кроме того, результаты вызова free () для освобождения объекта, выделенного новым, или использования delete для освобождения памяти, выделенной malloc (), не определены. Стандарт C ++ не гарантирует, что базовая реализация оператора new использует malloc (); фактически, в некоторых реализациях malloc () и new используют разные кучи. Проверьте эту ссылку

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

0 голосов
/ 25 июля 2011

Они не одинаковы. Оператор delete в C ++ вызывает деструктор объекта, который, в зависимости от реализации, должен освобождать память. Функция delete также может быть перегружена, тогда как free не может.

...