Почему new () / delete () медленнее, чем malloc () / free ()? - PullRequest
11 голосов
/ 03 апреля 2010

Почему new () / delete () медленнее, чем malloc () / free ()?

EDIT:

Спасибо за ответы до сих пор. Пожалуйста, укажите спецификации стандартной реализации C ++ для new () и delete (), если они у вас есть, спасибо!

Ответы [ 5 ]

26 голосов
/ 03 апреля 2010

Посмотрите на этот кусок кода C:

struct data* pd = malloc(sizeof(struct data));
init_data(pd);

Оператор new в C ++, по сути, делает то, что делает вышеуказанный фрагмент кода. Вот почему это медленнее, чем malloc().

Аналогично с delete. Это делает эквивалент этого:

deinit_data(pd);
free(pd);

Если конструкторы и деструкторы пусты (как для встроенных модулей), new и delete не должны быть медленнее, чем malloc() и free(). (Если они равны , это часто происходит из-за того, что обычные реализации вызывают malloc() / free() под капотом, поэтому они являются оберткой вокруг них. Оборачивание затрат. Также может существовать код, который нужно выяснить, что нельзя вызывать конструкторы / деструкторы. Это тоже будет стоить.)

Редактировать Чтобы ответить на дополнительный вопрос:

new и delete не являются функциями, они являются операторами. Это: new data() называется новым выражением . Это делает две вещи. Сначала он вызывает operator new, затем инициализирует объект, обычно вызывая соответствующий конструктор. (Я говорю «обычно», потому что встроенные модули не имеют конструкторов. Но новое выражение, включающее встроенные, работает тем же.)

Вы можете манипулировать обеими этими фазами. Вы можете создавать свои собственные конструкторы, чтобы манипулировать инициализацией ваших типов, и вы можете перегрузить operator new (даже с несколькими перегрузками, имеющими разные дополнительные аргументы, а также специально для каждого класса, если хотите), чтобы манипулировать выделением свободного хранилища. Если вы не реализуете собственный operator new, используется версия из стандартной библиотеки. Распространенная реализация этого вызывает malloc().

Аналогичным образом, если вы напишите delete pd, который называется delete expression , произойдут две вещи: в зависимости от pd, объект деинициализируется, обычно вызывая его деструктор, затем память освобожден путем вызова соответствующего operator delete.

Опять же, вы можете управлять обеими фазами, написав собственный деструктор и написав собственную версию operator delete. (Версия operator delete, входящая в стандартную библиотеку, часто используется для вызова free().)

13 голосов
/ 03 апреля 2010

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

4 голосов
/ 03 апреля 2010

Когда вызывается оператор new, происходят две вещи:

  1. Память выделяется для объекта в куче.
  2. Вызывается конструктор объекта.

Таким образом, из-за накладных расходов на строительство объектов new медленнее, чем malloc.

Аналогично, delete выполняет следующие две вещи:

  1. Вызывает деструктор объекта кучи.
  2. Освобождает память объекта.

Короче говоря, malloc выделяет только сырую память, тогда как new не только выделяет сыруюпамять, но также превращает необработанную память в объекты.

4 голосов
/ 03 апреля 2010

Если вы используете их для выделения «простых старых данных», так что конструктор / деструктор тривиальны, вряд ли они вообще существенно отличаются по скорости от malloc / free. Возможно (вероятно?), Что вы допустили ошибку где-то в своих измерениях, что привело к смещению результатов. На самом деле все, что они делают, кроме вызова malloc / free, это конструктор / деструктор исполняемого типа (несколько раз для массивов).

1 голос
/ 15 июня 2018

Их не должно быть, и их нет в кодовой базе, в которой я работаю.

Там, где я работаю, malloc / free работает медленнее и более неэффективно, чем new / delete по двум причинам:

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