Почему я должен использовать новое размещение? - PullRequest
12 голосов
/ 08 февраля 2012

Как кажется, placement new создает новый объект в предварительно выделенной памяти, значит ли это, что это займет меньше времени? Похоже, это быстрее, чем выделение с использованием старого обычного new. Тогда, если это так удобно и быстрее, почему бы не использовать placement new все время?

Ответы [ 6 ]

4 голосов
/ 08 февраля 2012

normal (nonplacement) new в основном эквивалентно выполнению

T* ptr = static_cast<T*>(malloc(sizeof(T)));
new(ptr) T;

Конечно, реальность выглядит немного иначе из-за проверки ошибок и тому подобного, но результат болееили меньше того же самого (через не идентичный, вы не можете delete указатель, выделенный таким образом, вместо этого вам нужно явно вызвать деструктор (ptr->~T()) и затем освободить память, используя free).

Таким образом, размещение new действительно должно быть быстрее, чем размещение без нового, так как не требуется выделять память.Однако проблема в том, что память должна быть где-то выделена.Таким образом, вы по существу заменили один вызов new на вызов placement new и некоторый код для выделения где-либо (если нет, то почему бы вы сначала использовали new?).Должно быть очевидно, что это менее удобно и более подвержено ошибкам.

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

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

3 голосов
/ 08 февраля 2012

Это просто не нужно для большинства программ, так как их шаблоны использования не делают это необходимым.Это не имеет значения для программ, которые не используют кучу так часто, и это трудно понять правильно (лучше, чем ваша операционная система, то есть).Также вы можете только выиграть, оптимизируя распределение.По большей части любая алгоритмическая оптимизация приведет к гораздо большему ускорению.Многие гарантии, которые может предложить настроенный распределитель (гарантированные ограничения времени для выделения через предварительно выделенную память, низкая фрагментация памяти), часто не нужны.

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

2 голосов
/ 08 февраля 2012

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

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

Это не единственное использование такого рода оператора new .Подробнее здесь .

Также помните, что размещение new не вызывает деструктор автоматически!Вы должны сделать foo->~Foo(); для своего Foo foo; вручную.

2 голосов
/ 08 февраля 2012

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

1 голос
/ 08 февраля 2012

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

Попытка сделать это для программ, которые на самом деле не нуждаются в этом, вероятно, только даст вам минимальное ускорение, но может стоить вам много часов в отладке.

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

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

void* buffer = aligned_malloc(sizeof(Object), 16); 
Object* object = new (buffer) Waypoint();

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

1 голос
/ 08 февраля 2012

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

...