указатель, а затем объект после нового оператора в C ++ [duplicate]

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

342
задан CharlesB 4 November 2013 в 13:24
поделиться

22 ответа

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

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

Devex дает хороший пример :

Стандартный C ++ также поддерживает оператор размещения new, который строит объект в предварительно выделенном буфере. Это полезно при создании пула памяти, сборщика мусора или просто в том случае, когда безопасность производительности и исключений является первостепенной (нет опасности сбоя распределения, поскольку память уже выделена, а построение объекта в предварительно выделенном буфере занимает меньше времени) :

char *buf  = new char[sizeof(string)]; // pre-allocated buffer
string *p = new (buf) string("hi");    // placement new
string *q = new string("hi");          // ordinary heap allocation

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

Освобождение места размещения new

Вы не должны освобождать все объекты, которые используют буфер памяти. Вместо этого вы должны удалить [] только исходный буфер. Затем вам придется вручную вызвать деструкторов ваших классов вручную. Для хорошего предложения по этому вопросу см. FAQ по Stroustrup: Есть ли «удаление места размещения» ?

317
ответ дан danijar 20 August 2018 в 08:38
поделиться
  • 1
    Он не устарел, так как вам нужна эта функция, чтобы эффективно реализовывать объекты контейнера (например, вектор). Если вы не создаете свой собственный контейнер, вам не нужно использовать эту функцию. – Martin York 21 October 2008 в 22:19
  • 2
    Также очень важно запомнить #include & lt; memory & gt ;, иначе вы можете столкнуться с некоторыми ужасными головными болями на некоторых платформах, которые автоматически не распознают размещение новых – Ramon Zarazua B. 24 September 2009 в 19:28
  • 3
    Строго, это неопределенное поведение, чтобы вызвать delete[] в исходном буфере char. Использование места размещения new закончило срок жизни исходных объектов char, повторно используя их хранилище. Если теперь вы назовете delete[] buf, динамический тип объекта (ов), на который указывает, больше не соответствует их статическому типу, так что у вас есть неопределенное поведение. Более последовательно использовать operator new / operator delete для выделения необработанной памяти, предназначенной для использования по месту размещения new. – CB Bailey 21 March 2010 в 16:10
  • 4
    Я определенно пропустил бы использование кучи в кардиостимуляторе :-) – Eli Bendersky 9 January 2011 в 09:42
  • 5
    @RamonZarazua Неверный заголовок, это #include <new>. – bit2shift 26 April 2016 в 03:46

Используется std::vector<>, потому что std::vector<> обычно выделяет больше памяти, чем objects в vector<>.

7
ответ дан Andreas Magnusson 20 August 2018 в 08:38
поделиться

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

/* Quickly aligns the given pointer to a power of two boundary IN BYTES.
@return An aligned pointer of typename T.
@brief Algorithm is a 2's compliment trick that works by masking off
the desired number in 2's compliment and adding them to the
pointer.
@param pointer The pointer to align.
@param boundary_byte_count The boundary byte count that must be an even
power of 2.
@warning Function does not check if the boundary is a power of 2! */
template <typename T = char>
inline T* AlignUp(void* pointer, uintptr_t boundary_byte_count) {
  uintptr_t value = reinterpret_cast<uintptr_t>(pointer);
  value += (((~value) + 1) & (boundary_byte_count - 1));
  return reinterpret_cast<T*>(value);
}

struct Foo { Foo () {} };
char buffer[sizeof (Foo) + 64];
Foo* foo = new (AlignUp<Foo> (buffer, 64)) Foo ();

Теперь не это просто положил улыбку на твоем лице (:-). I ♥♥♥ C ++ 1x

1
ответ дан Cale 20 August 2018 в 08:38
поделиться

Мы используем его с пользовательскими пулами памяти. Просто эскиз:

class Pool {
public:
    Pool() { /* implementation details irrelevant */ };
    virtual ~Pool() { /* ditto */ };

    virtual void *allocate(size_t);
    virtual void deallocate(void *);

    static Pool::misc_pool() { return misc_pool_p; /* global MiscPool for general use */ }
};

class ClusterPool : public Pool { /* ... */ };
class FastPool : public Pool { /* ... */ };
class MapPool : public Pool { /* ... */ };
class MiscPool : public Pool { /* ... */ };

// elsewhere...

void *pnew_new(size_t size)
{
   return Pool::misc_pool()->allocate(size);
}

void *pnew_new(size_t size, Pool *pool_p)
{
   if (!pool_p) {
      return Pool::misc_pool()->allocate(size);
   }
   else {
      return pool_p->allocate(size);
   }
}

void pnew_delete(void *p)
{
   Pool *hp = Pool::find_pool(p);
   // note: if p == 0, then Pool::find_pool(p) will return 0.
   if (hp) {
      hp->deallocate(p);
   }
}

// elsewhere...

class Obj {
public:
   // misc ctors, dtors, etc.

   // just a sampling of new/del operators
   void *operator new(size_t s)             { return pnew_new(s); }
   void *operator new(size_t s, Pool *hp)   { return pnew_new(s, hp); }
   void operator delete(void *dp)           { pnew_delete(dp); }
   void operator delete(void *dp, Pool*)    { pnew_delete(dp); }

   void *operator new[](size_t s)           { return pnew_new(s); }
   void *operator new[](size_t s, Pool* hp) { return pnew_new(s, hp); }
   void operator delete[](void *dp)         { pnew_delete(dp); }
   void operator delete[](void *dp, Pool*)  { pnew_delete(dp); }
};

// elsewhere...

ClusterPool *cp = new ClusterPool(arg1, arg2, ...);

Obj *new_obj = new (cp) Obj(arg_a, arg_b, ...);

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

50
ответ дан Don Wakefield 20 August 2018 в 08:38
поделиться
  • 1
    Приятно, но проблема заключается в том, чтобы эффективно определить Pool :: find_pool (void *) ... – jdkoftinoff 28 January 2011 в 17:53
  • 2
    Ага. Мы обходимся довольно умно, но это вопрос не по теме. – Don Wakefield 28 January 2011 в 21:28
  • 3
    @jdkoftinoff есть ли у вас какая-либо ссылка на фактический образец кода? Кажется довольно интересным для меня! – Victor 14 January 2017 в 11:26
  • 4
    @DonWakefield Как вы обрабатываете выравнивание в этом пуле? Разве вы не должны проходить выравнивание в качестве аргумента allocate()? – Mikhail Vasilyev 13 June 2018 в 17:16
  • 5
    @MikhailVasilyev, в реальной реализации, вы, конечно, справитесь с этим. Только пример кода. – Don Wakefield 13 June 2018 в 17:36

Голова: BINGO! Вы получили это полностью - это именно то, для чего он идеально подходит. Во многих встроенных средах внешние ограничения и / или сценарий общего использования заставляют программиста отделять выделение объекта от его инициализации. Скомпонованный вместе, C ++ называет это «экземпляр»; но всякий раз, когда действие конструктора должно быть явно вызвано без динамического или автоматического распределения, размещение нового - это способ сделать это. Это также идеальный способ найти глобальный объект C ++, привязанный к адресу аппаратного компонента (I / O с памятью) или для любого статического объекта, который по какой-либо причине должен находиться по фиксированному адресу.

12
ответ дан dorcsssc 20 August 2018 в 08:38
поделиться

Я использовал его для построения объектов, выделенных в стеке через alloca ().

бесстыдный плагин: я написал о нем здесь .

20
ответ дан Ferruccio 20 August 2018 в 08:38
поделиться
  • 1
    Очень здорово, но вы не справляетесь с проблемой alloca. – Motti 3 November 2008 в 09:11
  • 2
    интересная статья, но я не уверен, что понимаю преимущество использования этого над boost::array. Можете ли вы немного рассказать об этом? – GrahamS 10 February 2011 в 12:52
  • 3
    boost :: array требует, чтобы размер массива был константой времени компиляции. Это не имеет такого ограничения. – Ferruccio 10 February 2011 в 13:26
  • 4
    @Ferruccio Это довольно круто, я заметил, что ваш макрос немного небезопасен, хотя, а именно, размер может быть выражением. Если x + 1 передается, например, вы бы расширили его до sizeof (type) * x + 1, который был бы неправильным. Вам нужно скопировать макрос, чтобы сделать его более безопасным. – Benj 15 March 2012 в 13:22
  • 5
    Использование с alloca выглядит опасным для меня, если возникает исключение, поскольку вы должны вызвать деструкторы на всех ваших объектах. – CashCow 12 April 2013 в 12:13

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

Если все поддерживаемые типы значений по классу Variant являются типами POD (например, int, float, double, bool), тогда достаточно тегированного объединения C-стиля, но если вы хотите, чтобы некоторые из типов значений были объектами C ++ (например, std :: string), Функция C union не будет выполняться, поскольку типы данных, отличные от POD, не могут быть объявлены как часть объединения.

Поэтому вместо этого я выделяю массив байтов, который достаточно велик (например, sizeof (the_largest_data_type_I_support)) и использует размещение new для инициализации соответствующего объекта C ++ в этой области, когда для параметра Variant установлено значение этого типа. (И размещение удаляется заранее, если вы, конечно, переключаясь с другого типа данных, отличного от POD)

10
ответ дан Jeremy Friesner 20 August 2018 в 08:38
поделиться
  • 1
    Erm, типы данных, отличные от POD , могут объявляться в союзе, если вы предоставляете объединение ctor - и hey - то, что ctor , вероятно, будет использовать размещение new для инициализации его не-POD-подкласс. Ссылка: stackoverflow.com/a/33289972/2757035 Повторное использование этого колеса с использованием произвольно большого массива байтов является впечатляющим элементом акробатики, но кажется совершенно ненужным. Итак, что я пропустил? :) – underscore_d 20 November 2015 в 01:50
  • 2
    Вы пропустили все версии C ++ до C ++ 11, которые во многих случаях по-прежнему нуждаются в поддержке. :) – Jeremy Friesner 23 November 2015 в 03:33

Смотрите файл fp.h в проекте xll в http://xll.codeplex.com Он решает проблему «необоснованного chumminess с компилятором» для массивов, которые любят переносить свои размеры вокруг с ними.

typedef struct _FP
{
    unsigned short int rows;
    unsigned short int columns;
    double array[1];        /* Actually, array[rows][columns] */
} FP;
3
ответ дан Keith A. Lewis 20 August 2018 в 08:38
поделиться

Это может быть удобно при использовании разделяемой памяти, среди других применений ... Например: http://www.boost.org/doc/libs/1_51_0/doc/html/interprocess/synchronization_mechanisms.html# interprocess.synchronization_mechanisms.conditions.conditions_anonymous_example

5
ответ дан kralyk 20 August 2018 в 08:38
поделиться

Я использовал его для хранения объектов с файлами с памятью. Конкретным примером была база данных изображений, которая обрабатывала большое количество больших изображений (больше, чем могла бы поместиться в память).

6
ответ дан Martin Beckett 20 August 2018 в 08:38
поделиться

Я видел, что он использовался в качестве незначительного взлома производительности для указателя «динамического типа» (в разделе «Под капотом»):

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

6
ответ дан Max Lybbert 20 August 2018 в 08:38
поделиться
  • 1
    Что означает , если удерживаемое значение может помещаться внутри значения void * ? Его всегда можно присвоить любому типу указателя void *. Не могли бы вы показать нам пример? – anurag86 20 October 2015 в 14:06
  • 2
    @ anurag86: На моей 64-битной машине, void* занимает 8 байтов. Немного глупо указать восьмибайтный void* на однобайтный bool. Но вполне возможно наложить bool на void*, как на union { bool b; void* v }. Вам нужно каким-то образом узнать, что вещь, которую вы назвали void*, на самом деле является bool (или short, или float и т. Д.). В статье, в которой я расскажу, описывается, как это сделать. И, чтобы ответить на исходный вопрос, место размещения new - это функция, используемая для создания bool (или другого типа), где ожидается void* (приведение используется для последующего получения / изменения значения). – Max Lybbert 20 October 2015 в 16:12
  • 3
    @ anurag86: Это не одно и то же, но вас могут заинтересовать тегированные указатели ( ru.wikipedia.org/wiki/Tagged_pointer ). – Max Lybbert 20 October 2015 в 16:13

Полезно, если вы создаете ядро ​​- где вы помещаете код ядра, который вы читаете с диска или в pagetable? Вы должны знать, куда прыгать.

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

Я также считаю, что в некоторых реализациях STL используется новое размещение, например std :: vector. Таким образом, они выделяют место для 2 ^ n элементов и не нуждаются всегда в realloc.

7
ответ дан mstrobl 20 August 2018 в 08:38
поделиться
  • 1
    Сокращение распределения памяти является одной из основных причин его использования, а также «трюков». подобно загрузке объектов с диска – lefticus 21 October 2008 в 17:40
  • 2
    Я не знаю никаких ядер, написанных на C ++; большинство ядер написано на прямой C. – Adam Rosenfield 21 October 2008 в 17:50
  • 3
    Операционная система, с которой я узнал основы ОС, написана на C ++: sweb.sourceforge.net – mstrobl 21 October 2008 в 20:13

Одно место, через которое я столкнулся, находится в контейнерах, которые выделяют смежный буфер, а затем заполняют его объектами по мере необходимости. Как уже упоминалось, std :: vector может это сделать, и я знаю, что некоторые версии MFC CArray и / или CList сделали это (потому что именно там я впервые столкнулся с ним). Метод перераспределения буфера - очень полезная оптимизация, а размещение нового - это почти единственный способ построить объекты в этом сценарии. Он также иногда используется для создания объектов в блоках памяти, выделенных вне вашего прямого кода.

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

4
ответ дан Nick 20 August 2018 в 08:38
поделиться

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

Старый способ C использовал memset() для установки всех элементов на 0. Вы не можете сделать это на C ++ из-за vtables и конструкторов пользовательских объектов.

Поэтому я иногда использую следующие

 static Mystruct m;

 for(...)  {
     // re-initialize the structure. Note the use of placement new
     // and the extra parenthesis after Mystruct to force initialization.
     new (&m) Mystruct();

     // do-some work that modifies m's content.
 }
8
ответ дан nimrodm 20 August 2018 в 08:38
поделиться
  • 1
    Разве вам не нужно было бы сделать соответствующее разрушение, прежде чем повторно инициализировать его таким образом? – Head Geek 5 April 2013 в 04:17
  • 2
    [Отредактировано для орфографии] Обычно - вы делаете. Но иногда, когда вы знаете, что класс не выделяет память или другие ресурсы (или вы удалили их извне - например, когда вы используете пулы памяти), вы можете использовать эту технику. Это гарантирует, что указатели v-таблицы не будут перезаписаны. - nimrodm 16 часов назад – nimrodm 6 April 2013 в 19:54
  • 3
    Даже в C, используя установку всех битов в 0, гарантируется только получение представления 0 для интегральных типов, а не других типов (нулевой указатель может иметь ненулевое представление). – curiousguy 16 August 2015 в 14:20
  • 4
    @curiousguy - для примитивных типов вы правы (это сделает программу предсказуемой, что является преимуществом, когда дело доходит до отладки). Тем не менее, C ++ datatypes будет иметь свой конструктор работает (на месте) и будет правильно инициализирован. – nimrodm 16 August 2015 в 14:27

Механизмы сценариев могут использовать его в собственном интерфейсе для выделения собственных объектов из скриптов. Для примера см. Angelscript (www.angelcode.com/angelscript).

4
ответ дан Raindog 20 August 2018 в 08:38
поделиться

Размещение new также очень полезно при сериализации (скажем, с boost :: serialization). В 10 лет c ++ это только второй случай, когда мне нужно новое место для размещения (третий, если вы включаете интервью :)).

8
ответ дан RichardBruce 20 August 2018 в 08:38
поделиться

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

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

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

Я видел это на практике специально для VoxWorks RTOS, поскольку его система распределения памяти по умолчанию сильно страдает от фрагментации. Поэтому выделение памяти с помощью стандартного метода new / malloc было в основном запрещено в проекте. Все резервирования памяти должны поступать в выделенный пул памяти.

7
ответ дан rkachach 20 August 2018 в 08:38
поделиться

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

6
ответ дан Steve Fallows 20 August 2018 в 08:38
поделиться

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

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

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

26
ответ дан T.E.D. 20 August 2018 в 08:38
поделиться
  • 1
    Привет, TED, не могли бы вы рассказать больше о решении, которое у вас есть. Я думаю о заранее выделенном решении, но не получил большого прогресса. Заранее спасибо! – Viet 22 March 2010 в 13:38
  • 2
    Ну, фактический гетерогенный круговой буферный код действительно был сложной частью, чтобы получить право. Размещение нового выглядит немного ужасно, но для сравнения это не было проблемой. – T.E.D. 23 March 2010 в 14:40

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

Возьмите контейнеры наподобие unordered_map, vector или deque. Все они выделяют больше памяти, чем минимально требуется для вставленных вами элементов, чтобы избежать необходимости распределения кучи для каждой отдельной вставки. Давайте используем vector в качестве простейшего примера.

Когда вы это делаете:

vector<Foo> vec;

// Allocate memory for a thousand Foos:
vec.reserve(1000);

... который фактически не создает тысячу Foos. Он просто выделяет / резервирует память для них. Если vector не использовал здесь место размещения, это было бы построение по умолчанию Foos по всему месту, а также необходимость вызывать их деструкторы даже для элементов, которые вы никогда не вставили в первую очередь.

Allocation! = Construction, Freeing! = Destruction

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

Должно быть разделение между этими идеями, чтобы избежать излишнего вызова конструкторов и деструкторов излишне левым и правым, и поэтому стандартная библиотека разделяет идею std::allocator (которая не создает или не уничтожает элементы, когда он выделяет / освобождает память *) вдали от используемых им контейнеров, которые вручную создают элементы, используя размещение новых и вручную уничтожая элементы, используя явные вызовы деструкторов.

  • Ненавижу дизайн std::allocator, но это другой предмет, о котором я не буду говорить. : -D

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

Естественно, если вы когда-нибудь работаете с помощью пользовательских распределителей для выделения объектов по отдельности, например, в виде бесплатного списка, вы также обычно хотели бы использовать placement new, как это (основной пример, который не беспокоит безопасность исключений или RAII):

Foo* foo = new(free_list.allocate()) Foo(...);
...
foo->~Foo();
free_list.free(foo);
3
ответ дан Team Upvote 20 August 2018 в 08:38
поделиться

Это полезно, если вы хотите отделить выделение от инициализации. STL использует новое размещение для создания элементов контейнера.

43
ответ дан Tim Cooper 20 August 2018 в 08:38
поделиться

Как правило, размещение нового используется, чтобы избавиться от стоимости распределения «нормального нового».

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

5
ответ дан xtofl 20 August 2018 в 08:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: