Что означает «новое (& переменное) значение» в C ++?

17

Скажем, у меня есть следующий код в программе на C ++:

Object a = Object(someParameters);
new (&a) Object(someOtherParameters);

Я полагаю, что он заменяет содержимое a Object(someOtherParameters) , избегая возможного operator= , объявленного для Object . Правильно ли это?

    
задан MrMage 29.11.2012 в 14:14
источник
  • В стороне от существующих ответов: синтаксиса в названии вашего вопроса не существует! Вы не можете использовать этот синтаксис с любым значением, вы можете просто использовать его в вызове конструктора - то есть значение должно иметь форму T (аргументы). –  Konrad Rudolph 29.11.2012 в 14:20
  • место размещения новое всегда используется в пуле памяти C ++ (пул объектов). как дополнительный ответ. –  Healer 29.11.2012 в 14:22

2 ответа

21

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

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

char * rawMemory = new char [sizeof (Object)];

, и вы хотите построить объект в этой памяти. Вы вызываете

new(rawMemory) Object(params);

Теперь, прежде чем освободить память

delete [] rawMemory; 

вам нужно будет вызвать derstuctor объекта явно

reinterpret_cast<Object*>(rawMemory)->~Object();

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

Bonus: Вы когда-нибудь задавались вопросом, как стандартный std::vector может обойтись без содержащихся в нем объектов по умолчанию? Причина в том, что для большинства, если не для всех, реализаций allocator<T> не хранит T* p , что потребовало бы, чтобы T был конструктивным по умолчанию в случае p = new T[N] . Вместо этого он хранит char pointer - raw memory и выделяет p = new char[N*sizeof(T)] . Когда вы push_back объекта, он просто вызывает конструктор копирования с новым местом размещения на соответствующем адресе в этом массиве символов.

    
ответ дан Armen Tsirunyan 29.11.2012 в 14:15
  • Последнее предложение запутывает / ошибочно: деструктор автоматически вызывается в конце области действия до освобождения памяти объекта. Но перед тем, как перезаписать его, нужно вызвать деструктор для ранее существовавшего объекта. Для дополнительной пользы в этом ответе следует также упомянуть о возможности перегрузки оператора - потенциально перегрузка делает что-то совершенно другое. –  Konrad Rudolph 29.11.2012 в 14:18
  • @ KonradRudolph: Нет, это не так. Класс * object = новый (rawMemory) Класс (params); Вы не можете позже вызвать объект delete; потому что память не была назначена нормальным новым. Поэтому вам нужно вызвать object-> ~ Class () явно до вызова delete [] rawMemory. –  Armen Tsirunyan 29.11.2012 в 14:21
  • Объект в вопросе OP имеет выделение в стеке и правильный тип, поэтому ваше возражение не применяется. Даже для динамически распределенной памяти вы можете очень хорошо сделать следующее: T * x = new T; х-> ~ Т (); new (x) T (); удалить x; (обратите внимание на порядок вызова и размещения деструктора new!) –  Konrad Rudolph 29.11.2012 в 14:21
  • Как ответ, так и комментарий Konrad не учитывают, что это прекрасно (в соответствии со стандартом, удача в обзоре кода) не вызывать деструктор, если программа не зависит от побочных эффектов деструктора, как для старого объекта перед вызовом нового места размещения и нового объекта. –  David Rodríguez - dribeas 29.11.2012 в 14:25
  • Раздел Бонуса * неверен * / неточно. Большинство реализаций содержат T *, хотя и не получены с новым T []. Контейнер отслеживает, какая часть выделенной памяти и указана на то, что T * соответствует реальным объектам T и насколько она не инициализирована. –  David Rodríguez - dribeas 29.11.2012 в 15:34
6

Он известен как размещение new : он создает новый Object по адресу, указанному внутри круглых скобок. Размещение new обычно используется для создания объекта в необработанной памяти. Построение нового объекта поверх существующего, как это делает код, является плохой идеей, потому что он не вызывает деструктор на исходном объекте.

    
ответ дан Pete Becker 29.11.2012 в 14:16