Какие варианты использования для "размещения новых"? - PullRequest
370 голосов
/ 21 октября 2008

Кто-нибудь здесь когда-либо использовал "размещение нового" в C ++? Если да, то для чего? Мне кажется, это было бы полезно только на оборудовании с отображением памяти.

Ответы [ 22 ]

8 голосов
/ 21 октября 2008

Это полезно, если вы собираете ядро ​​- куда вы помещаете код ядра, который вы читаете с диска или из таблицы? Вам нужно знать, куда прыгать.

Или в других, очень редких случаях, например, когда у вас много выделенной комнаты и вы хотите разместить несколько конструкций друг за другом. Они могут быть упакованы таким образом без необходимости использования оператора offsetof (). Однако для этого есть и другие приемы.

Я также считаю, что некоторые реализации STL используют размещение новых, таких как std :: vector. Таким образом, они выделяют место для 2 ^ n элементов и не всегда должны перераспределять.

7 голосов
/ 21 октября 2008

Я использовал его для хранения объектов с отображенными в память файлами.
Конкретным примером была база данных изображений, которая обрабатывала большое количество больших изображений (больше, чем могло поместиться в памяти).

7 голосов
/ 21 октября 2008

Используется std::vector<>, потому что std::vector<> обычно выделяет больше памяти, чем objects в vector<>.

7 голосов
/ 22 октября 2008

Я видел, как он использовал незначительное снижение производительности для указателя «динамического типа» (в разделе «Под капотом»):

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

7 голосов
/ 16 января 2018

Фактически требуется реализовать любой тип структуры данных, которая выделяет больше памяти, чем минимально необходимое для количества вставляемых элементов (т. Е. Все, кроме связанной структуры, которая выделяет один узел за раз).

Возьмите контейнеры типа unordered_map, vector или deque. Все они выделяют больше памяти, чем минимально требуется для элементов, которые вы вставили до сих пор, чтобы избежать необходимости выделения кучи для каждой отдельной вставки. Давайте использовать vector в качестве простейшего примера.

Когда вы делаете:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

... это на самом деле не создает тысячу фоос. Он просто выделяет / резервирует память для них. Если бы vector не использовал размещение new здесь, это было бы созданием по умолчанию Foos повсюду, а также вызовом их деструкторов даже для элементов, которые вы даже никогда не вставляли в первую очередь.

Распределение! = Строительство, Освобождение! = Разрушение

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

Должно быть разделение между этими идеями, чтобы избежать ненужного вызова конструкторов и деструкторов без необходимости влево и вправо, и поэтому стандартная библиотека разделяет идею std::allocator (которая не создает и не уничтожает элементы, когда выделяет / освобождает память *) от контейнеров, которые ее используют, которые создают элементы вручную с помощью размещения новых и уничтожают элементы вручную, используя явные вызовы деструкторов.

  • Я ненавижу дизайн std::allocator, но это другая тема, о которой я не буду рассказывать. : -D

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

Естественно, если вы когда-либо работаете с пользовательскими распределителями для индивидуального размещения объектов, например, со свободным списком, тогда вам, как правило, также нужно использовать placement new, как это (основной пример, который не беспокоится об исключительной безопасности или RAII ):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);
6 голосов
/ 21 октября 2008

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

5 голосов
/ 21 октября 2008

Как правило, размещение нового используется, чтобы избавиться от стоимости размещения «нормального нового».

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

5 голосов
/ 29 августа 2012

Это может быть удобно при использовании разделяемой памяти, среди прочего ... Например: http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example

4 голосов
/ 21 октября 2008

Единственное место, где я столкнулся, это контейнеры, которые выделяют непрерывный буфер и затем заполняют его объектами по мере необходимости. Как уже упоминалось, std :: vector может сделать это, и я знаю, что некоторые версии MFC CArray и / или CList делали это (потому что именно там я впервые столкнулся с этим). Метод перераспределения буфера является очень полезной оптимизацией, и размещение new является практически единственным способом создания объектов в этом сценарии. Он также иногда используется для создания объектов в блоках памяти, выделенных вне вашего прямого кода.

Я использовал его в аналогичном качестве, хотя и не часто. Это полезный инструмент для набора инструментов C ++.

4 голосов
/ 22 октября 2008

Скриптовые движки могут использовать его в собственном интерфейсе для выделения собственных объектов из скриптов. См. Angelscript (www.angelcode.com/angelscript) для примеров.

...