Каковы варианты использования конструкции C ++ «размещение нового»? - PullRequest
13 голосов
/ 12 декабря 2008

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

 #include <new>        // Must #include this to use "placement new"
 #include "Fred.h"     // Declaration of class Fred

 void someCode()
 {
   char memory[sizeof(Fred)];
   void* place = memory;

   Fred* f = new(place) Fred();   // Create a pointer to a Fred(),
                                  // stored at "place"

   // The pointers f and place will be equal

   ...
 } 

(пример из C ++ FAQ Lite )

В этом примере указатель this Фреда будет равен place.


Я видел, как он использовался в коде нашей команды один или два раза. По вашему опыту, что позволяет эта конструкция? У других языков указателей есть подобные конструкции? Мне кажется, это напоминает equivalence в FORTRAN, который позволяет разным переменным занимать одно и то же место в памяти.

Ответы [ 12 ]

15 голосов
/ 12 декабря 2008

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

Подобные вещи делались и в C, но поскольку в C нет конструкторов, для них не требовалась языковая поддержка.

12 голосов
/ 12 декабря 2008

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

7 голосов
/ 12 декабря 2008

Полезно при создании собственных контейнеров, подобных объектам.

Например, если вы хотите создать вектор. Если вы резервируете место для большого количества объектов, вы хотите выделить память каким-либо методом, который не вызывает конструктор объекта (например, new char [sizeof (object) * reserveSize]). Затем, когда люди начинают добавлять объекты в вектор, вы используете новое размещение, чтобы скопировать их в выделенную память.

template<typename T>
class SillyVectorExample
{
    public:
        SillyVectorExample()
            :reserved(10)
            ,size(0)
            ,data(new char[sizeof(T) * reserved])
        {}
        void push_back(T const& object)
        {
            if (size >= reserved)
            {
                // Do Somthing.
            }
            // Place a copy of the object into the data store.
            new (data+(sizeof(T)*size))  T(object);
            ++size;
        }
        // Add other methods to make sure data is copied and dealllocated correctly.
    private:
        size_t   reserved;
        size_t   size;
        char*    data;
 };

PS. Я не защищаю это. Это просто упрощенный пример того, как могут работать контейнеры.

7 голосов
/ 12 декабря 2008

Я использовал его при построении объектов в сегменте общей памяти.

5 голосов
/ 12 декабря 2008

Placement new можно использовать для создания безопасных для типов союзов, таких как Boost's variant.

Класс union содержит буфер размером с самый большой тип, который он содержит (и с достаточным выравниванием). Он помещает new s объекты в буфер по мере необходимости.

4 голосов
/ 13 декабря 2008

Placement new НЕ предназначен для выравнивания указателей (вы можете просто использовать это назначение!).

Размещение нового предназначено для построения объекта в определенном месте. Существует три способа конструирования объекта в C ++, и размещение new является единственным, который дает вам явный контроль над тем, где этот объект «живет». Это полезно для нескольких вещей, включая разделяемую память, низкоуровневый ввод / вывод устройства и реализацию пула / распределителя памяти.

При выделении стека объект создается на вершине стека, где бы он ни находился в настоящее время.

При использовании «обычного» new объект создается по фактически произвольному адресу в куче, как это управляется стандартной библиотекой (если вы не переопределили оператор new).

Размещение new говорит: «Создайте мне объект по этому адресу специально», и его реализация - просто перегрузка оператора new, который возвращает переданный ему указатель, как средство перехода к остальной части механизма нового оператора. , который создает объект в памяти, возвращаемый оператором новой функции.

Стоит также отметить, что оператор новой функции может быть перегружен произвольными аргументами (как и любая другая функция). Эти другие аргументы передаются через синтаксис "new (arg 2, arg3, ..., argN)". Arg1 всегда неявно передается как "sizeof (что бы вы ни создавали)".

4 голосов
/ 12 декабря 2008

Я использую эту конструкцию при выполнении C ++ в режиме ядра.

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

Все это обернуто в классы и функции, но в конце я делаю новое размещение.

2 голосов
/ 13 декабря 2008

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

1 голос
/ 13 декабря 2008

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

1 голос
/ 12 декабря 2008

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...