Кто-нибудь здесь когда-либо использовал "размещение нового" в C ++? Если да, то для чего? Мне кажется, это было бы полезно только на оборудовании с отображением памяти.
c++
memory-management
new-operator
placement-new
Главный Компьютерщик
источник
источник
p = pt
и использовать оператор присваиванияPoint
вместо выполненияnew(&p) Point(pt)
? Я удивляюсь разнице между ними. Будет ли первая вызыватьoperator=
Point, а вторая - копировать конструкторPoint
? но мне все еще не очень понятно, почему один лучше другого.U::operator=
только что был вызван.Ответы:
Размещение нового позволяет вам создать объект в памяти, который уже выделен.
Возможно, вы захотите сделать это для оптимизации, когда вам нужно создать несколько экземпляров объекта, и быстрее не перераспределять память каждый раз, когда вам нужен новый экземпляр. Вместо этого может быть более эффективно выполнить одно выделение для куска памяти, который может содержать несколько объектов, даже если вы не хотите использовать все это одновременно.
DevX дает хороший пример :
Вы также можете быть уверены, что не может быть ошибки выделения в определенной части критического кода (например, в коде, выполняемом кардиостимулятором). В этом случае вы захотите выделить память раньше, а затем использовать новое размещение в критическом разделе.
Распределение в размещении новых
Вы не должны освобождать каждый объект, который использует буфер памяти. Вместо этого вы должны удалить [] только оригинальный буфер. Затем вам придется вызывать деструкторы ваших классов вручную. Хорошее предложение по этому вопросу см. В разделе часто задаваемых вопросов Страуструпа: « Есть ли удаление места размещения» ?
источник
delete[]
исходногоchar
буфера. Использование размещенияnew
закончило время жизни исходныхchar
объектов, повторно использовав их хранилище. Если вы теперь вызываетеdelete[] buf
динамический тип объекта (ов), на который указывают, он больше не соответствует их статическому типу, поэтому у вас неопределенное поведение. Более логично использоватьoperator new
/operator delete
для выделения необработанной памяти, предназначенной для использования путем размещенияnew
.#include <new>
.Мы используем его с пользовательскими пулами памяти. Просто набросок:
Теперь вы можете кластеризовать объекты в одной области памяти, выбрать распределитель, который очень быстр, но не освобождает память, использовать отображение памяти и любую другую семантику, которую вы хотите наложить, выбрав пул и передав его в качестве аргумента для размещения объекта новый оператор.
источник
allocate()
где-то?Это полезно, если вы хотите отделить распределение от инициализации. STL использует размещение новых для создания элементов контейнера.
источник
Я использовал это в программировании в реальном времени. Обычно мы не хотим выполнять какое-либо динамическое распределение (или освобождение) после запуска системы, потому что нет никакой гарантии, сколько времени это займет.
Что я могу сделать, так это предварительно выделить большой кусок памяти (достаточно большой, чтобы вместить любое количество того, что может потребоваться классу). Затем, как только я выясню во время выполнения, как создавать объекты, можно использовать новое размещение, чтобы создавать объекты именно там, где я их хочу. Я знаю, что использовал одну из них, чтобы помочь создать гетерогенный кольцевой буфер .
Это, конечно, не для слабонервных, но именно поэтому они делают синтаксис для этого довольно грубым.
источник
Я использовал его для создания объектов, размещенных в стеке, с помощью alloca ().
бесстыдная вилка: я писал об этом здесь .
источник
boost::array
. Можете ли вы рассказать об этом немного?Главный Компьютерщик: БИНГО! Вы получили это полностью - это именно то, для чего это идеально. Во многих встроенных средах внешние ограничения и / или сценарий общего использования вынуждают программиста отделить выделение объекта от его инициализации. С ++, объединившись, называет это «созданием экземпляра»; но всякий раз, когда действие конструктора должно быть явно вызвано БЕЗ динамического или автоматического выделения, размещение нового - способ сделать это. Это также идеальный способ найти глобальный объект C ++, прикрепленный к адресу аппаратного компонента (ввод-вывод с отображением в памяти) или для любого статического объекта, который по какой-либо причине должен находиться по фиксированному адресу.
источник
Я использовал его для создания класса Variant (то есть объекта, который может представлять одно значение, которое может быть одним из множества различных типов).
Если все типы значений, поддерживаемые классом Variant, являются типами POD (например, int, float, double, bool), тогда достаточно тегированного объединения в стиле C, но если вы хотите, чтобы некоторые типы значений были объектами C ++ ( например, std :: string), функция объединения C не подойдет, поскольку типы данных, не относящиеся к POD, не могут быть объявлены как часть объединения.
Поэтому вместо этого я выделяю байтовый массив, который является достаточно большим (например, sizeof (the_largest_data_type_I_support)), и использую размещение new, чтобы инициализировать соответствующий объект C ++ в этой области, когда Variant установлен для хранения значения этого типа. (И размещение удаляется заранее при переключении с другого типа данных, не POD, конечно)
источник
new
для инициализации своего подкласса , не являющегося POD. Ссылка: stackoverflow.com/a/33289972/2757035 Изобретать это колесо с использованием произвольно большого массива байтов - это впечатляющая акробатика, но она кажется совершенно ненужной. Итак, что я пропустил? :)Размещение new также очень полезно при сериализации (скажем, с boost :: serialization). За 10 лет c ++ это только второй случай, для которого мне нужно было разместить новое (третий, если вы включаете интервью :)).
источник
Это также полезно, когда вы хотите повторно инициализировать глобальные или статически распределенные структуры.
Старый способ C использовал
memset()
для установки всех элементов на 0. Вы не можете сделать это в C ++ из-за vtables и пользовательских конструкторов объектов.Поэтому я иногда использую следующее
источник
Я думаю, что это не было выделено ни одним ответом, но другой хороший пример и использование для нового размещения - уменьшить фрагментацию памяти (с помощью пулов памяти). Это особенно полезно во встроенных системах и системах с высокой доступностью. В этом последнем случае это особенно важно, потому что для системы, которая должна работать 24/365 дней, очень важно не иметь фрагментации. Эта проблема не имеет ничего общего с утечкой памяти.
Даже когда используется очень хорошая реализация malloc (или аналогичная функция управления памятью), очень трудно долго справляться с фрагментацией. В какой-то момент, если вы не будете умело управлять вызовами резервирования / освобождения памяти, вы можете получить множество небольших пробелов , которые трудно использовать повторно (назначить новым резервированиям). Таким образом, одним из решений, которые используются в этом случае, является использование пула памяти для выделения перед рукой памяти для объектов приложения. После этого каждый раз, когда вам нужна память для какого-либо объекта, вы просто используете новое размещение, чтобы создать новый объект в уже зарезервированной памяти.
Таким образом, после запуска приложения у вас уже есть вся необходимая память. Все новое резервирование / освобождение памяти направляется в выделенные пулы (у вас может быть несколько пулов, по одному для каждого отдельного класса объектов). В этом случае не происходит фрагментации памяти, поскольку в ней нет пробелов, и ваша система может работать в течение очень длительных периодов (лет), не подвергаясь фрагментации.
Я видел это на практике специально для ОСРВ VxWorks, поскольку система распределения памяти по умолчанию сильно страдает от фрагментации. Поэтому выделение памяти с помощью стандартного метода new / malloc в проекте было в основном запрещено. Все резервирования памяти должны идти в выделенный пул памяти.
источник
Фактически требуется реализовать любой тип структуры данных, которая выделяет больше памяти, чем минимально требуется для количества вставляемых элементов (т. Е. Все, кроме связанной структуры, которая выделяет один узел за раз).
Принимать контейнеры нравится
unordered_map
,vector
илиdeque
. Все они выделяют больше памяти, чем минимально требуется для элементов, которые вы вставили до сих пор, чтобы избежать необходимости выделения кучи для каждой отдельной вставки. Давайте использоватьvector
в качестве простейшего примера.Когда вы делаете:
... это на самом деле не построить тысячу Фоос. Он просто выделяет / резервирует память для них. Если
vector
бы здесь не использовалось размещение new, этоFoos
повсеместно создавало бы по умолчанию, а также вызывало бы их деструкторы даже для элементов, которые вы вообще никогда не вставляли.Распределение! = Строительство, Освобождение! = Разрушение
Говоря в общем, для реализации многих структур данных, подобных описанному выше, вы не можете рассматривать выделение памяти и конструирование элементов как одну неделимую вещь, и вы также не можете рассматривать освобождение памяти и уничтожение элементов как одну неделимую вещь.
Должно быть разделение между этими идеями, чтобы избежать ненужного вызова конструкторов и деструкторов без необходимости влево и вправо, и поэтому стандартная библиотека отделяет идею
std::allocator
(которая не создает и не уничтожает элементы, когда она выделяет / освобождает память *) от контейнеры, которые его используют, которые создают элементы вручную с помощью размещения новых и уничтожают элементы вручную, используя явные вызовы деструкторов.Так или иначе, я имею тенденцию использовать это много, так как я написал много стандартных C ++ контейнеров общего назначения, которые не могли быть построены с точки зрения существующих. В их числе небольшая векторная реализация, которую я создал пару десятилетий назад, чтобы избежать выделения кучи в обычных случаях, и эффективная память (не выделяет один узел за раз). В обоих случаях я не мог по-настоящему реализовать их, используя существующие контейнеры, и поэтому мне пришлось использовать их,
placement new
чтобы избежать лишнего вызова конструкторов и деструкторов для ненужных вещей слева и справа.Естественно, если вы когда-либо работаете с пользовательскими распределителями, чтобы распределять объекты по отдельности, например, в виде свободного списка, вам также, как правило, нужно использовать
placement new
вот так (базовый пример, который не беспокоит исключительная безопасность или RAII):источник
Это полезно, если вы собираете ядро - куда вы помещаете код ядра, который вы читаете с диска или из таблицы? Вы должны знать, где прыгать.
Или в других, очень редких случаях, например, когда у вас много выделенного помещения и вы хотите разместить несколько конструкций друг за другом. Они могут быть упакованы таким образом без необходимости использования оператора offsetof (). Однако для этого есть и другие приемы.
Я также считаю, что некоторые реализации STL используют новые размещения, такие как std :: vector. Таким образом, они выделяют место для 2 ^ n элементов и не всегда должны перераспределяться.
источник
Он используется
std::vector<>
потому, чтоstd::vector<>
обычно выделяет больше памяти, чем естьobjects
вvector<>
.источник
Я использовал его для хранения объектов с отображенными в память файлами.
Конкретным примером была база данных изображений, которая обрабатывала большое количество больших изображений (больше, чем могло поместиться в памяти).
источник
Я видел, как это использовалось в качестве небольшого снижения производительности для указателя «динамического типа» (в разделе «Под капотом»):
источник
void*
занимает 8 байтов. Немного глупо указывать восемь байтvoid*
на один байтbool
. Но вполне возможно на самом деле наложитьbool
наvoid*
, очень какunion { bool b; void* v }
. Вам нужен какой-то способ узнать, что то, что вы называете, наvoid*
самом деле являетсяbool
(или ashort
, или afloat
и т. Д.). Статья, на которую я ссылаюсь, описывает, как это сделать. И, чтобы ответить на исходный вопрос, размещениеnew
- это функция, используемая для созданияbool
(или другого типа), гдеvoid*
ожидается a (приведения используются для последующего получения / изменения значения).Я использовал его для создания объектов на основе памяти, содержащей сообщения, полученные из сети.
источник
Как правило, размещение нового используется, чтобы избавиться от стоимости размещения «нормального нового».
Другой сценарий, в котором я использовал его, - это место, где я хотел получить доступ к указателю на объект, который еще должен был быть создан, для реализации отдельного документа на документ.
источник
Это может быть удобно при использовании разделяемой памяти, среди прочего ... Например: http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html#interprocess.synchronization_mechanisms.conditions. conditions_anonymous_example
источник
Единственное место, где я столкнулся с ним, - это контейнеры, которые выделяют непрерывный буфер и затем заполняют его объектами по мере необходимости. Как уже упоминалось, std :: vector может сделать это, и я знаю, что некоторые версии MFC CArray и / или CList делали это (потому что именно там я впервые столкнулся с этим). Метод перераспределения буфера является очень полезной оптимизацией, и размещение new является практически единственным способом создания объектов в этом сценарии. Это также иногда используется для создания объектов в блоках памяти, размещенных вне вашего прямого кода.
Я использовал его в аналогичном качестве, хотя это не часто встречается. Это полезный инструмент для набора инструментов C ++.
источник
Механизмы сценариев могут использовать его в собственном интерфейсе для выделения собственных объектов из сценариев. См. Angelscript (www.angelcode.com/angelscript) для примеров.
источник
См. Файл fp.h в проекте xll по адресу http://xll.codeplex.com. Он решает проблему «необоснованной болтовни с компилятором» для массивов, которым нравится носить с собой свои размеры.
источник
Вот убийственное использование для конструктора на месте C ++: выравнивание по строке кэша, а также другие степени 2 границ. Вот мой сверхбыстрый алгоритм выравнивания указателя для любой степени 2 границ с 5 или менее инструкциями одного цикла :
Теперь разве это не вызывает улыбку на лице (:-). Я ♥♥♥ C ++ 1x
источник