2012-02-07 4 views
11

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

+4

Это может помочь: http://www.parashift.com/c++-faq-lite/dtors.html#faq-11.10 –

+0

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

+1

@ron - Что делать, если у вас нет предопределенной памяти? –

ответ

4

нормальный (nonplacement) new в основном эквивалентна делать

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

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

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

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

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

+0

http://stackoverflow.com/questions/184537/in-what-cases-do-i-use-malloc-vs-new/7970036#7970036 – Flexo

+0

@awoodland: Ваша точка в том, что именно? – Grizzly

+0

Я считаю, что вы почти наверняка заново изобретаете «новый», используя размещение 'new' +' malloc' – Flexo

2

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

+2

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

3

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

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

+0

. так любезно объяснить себя? Я попытался дать сбалансированный ответ на то, что фактически спросил ОП. Возможно, я не знаком с другой огромной причиной, чтобы не использовать «размещение нового». – pmr

+0

Предположительно потому, что 1) это фактически не отвечает на вопрос, 2) плакат не указывал на свой прецедент, но если они спрашивают об этом, почему бы не воспитывать их? 3) операционная система построена для общего случая; размещение новых позволяет конкретным программам реализовать распределители, идеально подходящие для их конкретного использования. Предоставление общего «это, вероятно, не нужно» не полезно, если в сочетании с фактическим ответом. – jzila

+0

@jzila У меня сложилось впечатление, что ОП спрашивает об общем случае: почему часто место размещения не используется? Я попытался уделить больше внимания различным областям в редактировании. – pmr

2

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

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

Это не одноразовый оператор . Подробнее here.

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

1

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

1

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

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

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

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

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

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

Смежные вопросы