Применимое правило для этого изложено в §3.8 [базовое.жизнь]/р1 и 4:
Время жизни объекта типа T
заканчивается, когда:
- если Т тип класса с нетривиальным деструктора (12.4), запускается деструктор вызов , или
- Хранилище, которое объект занимает, повторно используется или освобождается.
4 Программы может закончиться сроком службы любого объекта путем повторного хранение которой объект занимает или путем явного вызова деструктора для объекта типа класса с нетривиальным деструктором. Для объекта типа класса с нетривиальным деструктором программа не , требуемая для вызова деструктора явно перед хранилищем, которое объект занимает повторно или освобожден; однако, если нет явного вызова деструктора или если delete-expression (5.3.5) - , который не используется для освобождения хранилища, деструктор не должен быть неявным образом и любая программа, которая зависит от стороны эффекты , созданные деструктором, имеют неопределенное поведение.
Так A *b = new (a) B;
повторно на хранение A
объекта, созданного в предыдущем заявлении, которое вполне определенное поведение при условии, что sizeof(A) >= sizeof(B)
*. То, что время жизни объекта A
закончилось в силу того, что его хранилище повторно используется. Деструктор A
не вызывается для этого объекта, и если ваша программа зависит от побочного эффекта, создаваемого этим деструктором, у него есть неопределенное поведение.
Приведенный вами параграф, §3.8 [basic.life]/p7, регулирует, когда указатель/ссылка на исходный объект может быть повторно использован. Поскольку этот код не удовлетворяет критериям, перечисленным в этом пункте, вы можете использовать только a
только в ограниченных путях, разрешенных §.3.8 [basic.life]/p5-6, или неопределенных результатах поведения (пример и сноска опущены):
5 Перед началом жизни объекта началась, но после хранения которого объект будет занимать был выделен или после жизни объекта закончился и перед хранением которой объект занят повторно используется или выпущенный, может использоваться любой указатель, который ссылается на хранилище , где может находиться или находился объект, но только в ограниченных количествах. По строительству или уничтожению объекта см. 12.7. В противном случае такой указатель относится к выделенному хранилищу (3.7.4.2) и с использованием указателя, как если бы указатель имел тип void*
, имеет значение . Такой указатель может быть разыменован, но полученное значение может использоваться только ограниченным образом, как описано ниже.Программа имеет неопределенное поведение, если:
- объект будет или была типа класса с нетривиальным деструктором и указатель используется в качестве операнда удалить-выражение,
- указатель используется для доступа к нестатическому элементу данных или вызова нестатической функции-члена объекта, или
- указатель неявно преобразован (4.10) в указатель на тип базового класса или
- указатель используется как операнд
static_cast
(5.2.9) (за исключением того, когда преобразование является void*
или void*
и впоследствии char*
или unsigned char*
), или
- указатель используется в качестве операнда
dynamic_cast
(5.2.7).
6 Аналогичным образом, до того, как срок службы объекта началось, но после того, как хранения которой объект будет занимать было выделено или, после того, как время жизни объекта закончилась и перед хранением которой объект занимал повторно используется или освобождается, любое значение gl, которое ссылается на исходный объект , может использоваться, но только ограниченным образом. Для объекта под строительство или уничтожение, см. 12.7. В противном случае такой glvalue относится к выделенному хранилищу (3.7.4.2), и использование свойств значения , которое не зависит от его значения, является корректным. Программа имеет неопределенное поведение, если:
- именующее к Rvalue преобразования (4.1) применяется к такому glvalue,
- glvalue используется для доступа к нестатический элемент данных или вызов не -static функция член объекта или
- glvalue неявно преобразуется (4.10) в отношении типа базового класса, или
- glvalue используется в качестве операнда
static_cast
(5.2.9), за исключением, когда конверсия в конечном счете равна cv char&
или cv unsigned char&
, или
- glvalue используется как операнд
dynamic_cast
(5.2.7) или как операнд typeid
.
* Для предотвращения UB от случаев, когда sizeof(B) > sizeof(A)
, мы можем переписать A *a = new A;
в char c[sizeof(A) + sizeof(B)]; A* a = new (c) A;
.
Есть ли A * b = новый (a) B; 'даже компилировать? –
Он должен скомпилировать, так как 'B' происходит от' A'. –
Компилятору не требуется реализовать пустую оптимизацию базового класса для удаления дополнительного пространства «A» с «B». Таким образом, вы не можете гарантировать, что 'sizeof (A)> = sizeof (B)', даже если он разрешен, он не переносится. –