Что такое использование конструкции С++ "размещение нового"?

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

 #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

   ...
 } 

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

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


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

Ответы

Ответ 1

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

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

Ответ 2

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

Ответ 3

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

Ответ 4

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

Например, если вы должны были создать вектор. Если вы зарезервируете место для большого количества объектов, вы хотите выделить память каким-либо методом, который не вызывает конструктор объекта (например, новый 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. Я не выступаю за это. Это просто упрощенный пример того, как контейнеры могут работать.

Ответ 5

Размещение new может использоваться для создания типов безопасных соединений, таких как Boost variant.

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

Ответ 6

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

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

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

Ответ 7

Размещение нового не означает, что указатели равны (вы можете просто использовать назначение для этого!).

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

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

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

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

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

Ответ 8

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

Ответ 9

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

Ответ 10

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

Ответ 11

мне кажется как способ выделения объекта в стеке.

Ответ 12

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