Стандартной показывает этот пример § 3.8 67 N3690:
struct C {
int i;
void f();
const C& operator=(const C&);
};
const C& C::operator=(const C& other) {
if (this != &other) {
this->~C(); // lifetime of *this ends
new (this) C(other); // new object of type C created
f(); // well-defined
}
return *this;
}
C c1;
C c2;
c1 = c2; // well-defined
c1.f(); // well-defined; c1 refers to a new object of type C
Обратите внимание, что этот пример прекращения жизни объекта перед созданием нового объекта на месте (сравните свой код, который не вызывает деструктор).
Но даже если вы сделали, стандарт также говорит:
Если после жизни объекта закончилась и перед хранением которого объект занят повторно используется или отпущена, новый объект является созданный в месте хранения, в котором был загружен исходный объект, указатель , указывающий на исходный объект, ссылка, которая ссылалась на исходный объект , или имя исходного объекта автоматически ссылаются на новый объект и, время жизни нового объекта , его можно использовать для управления n РЭБ объект, если:
- хранилище для нового объекта точно перекрывает место хранения которого исходный объект занимаемого, и - новый объект имеет же типа, что и исходный объект (не обращая внимания на высший уровень CV-классификаторы) и
- тип исходного объекта не Const квалификации, и, если тип класса, не содержит какой-либо нестатический элемент данных, типа которого Const-квалифицированной или ссылки тип и
- первоначальный объект был самым производным объектом (1.8) of тип T и новый объект является наиболее производным объектом типа T (то есть они не являются подобъектами базового класса).
обратите внимание на слова «и», все условия должны быть выполнены.
Поскольку вы не выполняете все условия (вы производный объект расположенной в пространство памяти объекта базового класса), то есть неопределенного поведение при ссылках на вещи с явным или неявным использованием этого указатель.
В зависимости от реализации компилятора это может или, возможно, в настоящее время взрывать, так как виртуальный объект базового класса сохраняет некоторое пространство для виртуальных таблиц, на месте построения объекта производного типа, который переопределяет некоторые из виртуальных функций означают, vtable может быть разным, поставить вопросы выравнивания и другие низкоуровневые внутренние элементы, и вы получите, что простого sizeof недостаточно, чтобы определить, правильный ли ваш код или нет.
Размещение-новое предполагается использовать на большинстве производных классов и заменять их объектами того же типа. Это еще одна причина, по которой у вас есть UB, потому что вы не только заменяете подобъект базового класса, но и заменяете его объектом другого типа. – 0x499602D2
@ 0x499602D2 18.6.1.3 Стандарта определяет поведение такого размещения - новое, но ничего не говорит о предполагаемом использовании ** на большинстве производных классов и создании объектов того же типа. ** –
3.8 «Если после срок службы объекта закончился [...], новый объект создается в месте хранения, в котором был загружен исходный объект, [...] имя исходного объекта [...] будет автоматически ссылаться на новый объект [...] и может быть используется для управления новым объектом [...], если: исходный объект был наиболее производным объектом (1.8) типа T, а новый объект является наиболее производным объектом типа T (т. е. они не являются подобъектами базового класса) ». – 0x499602D2