The*_*Zoo 5 c++ polymorphism placement-new language-lawyer
是否可以使用placement-new来更改多态对象的类型?如果没有,标准中究竟禁止它的是什么?
考虑以下代码:
#include <new>
struct Animal {
Animal();
virtual ~Animal();
virtual void breathe();
void kill();
void *data;
};
struct Dead: Animal {
void breathe() override;
};
void Animal::kill() {
this->~Animal();
new(this) Dead;
}
Run Code Online (Sandbox Code Playgroud)
称"杀人"是否合法?
更新:早期的注释没有根据此处所示的编程技术标准来解决(il)合法性,即通过显式调用析构函数来更改对象的类型,并为兼容的新对象应用placement-new.
因为有兴趣为什么有人愿意这样做,我可以提一下导致我提出问题的用例,尽管它与我提出的问题无关.
想象一下,您有一个具有多个虚拟方法的多态类型层次结构.在对象的生命周期中,发生的事情可以在代码中建模,因为对象会更改其类型.有许多完美合法的方法来编程,例如,将对象保持为指针,智能与否,以及交换其他类型的副本.但这可能很昂贵:必须将原始对象克隆或移动到另一个不同类型的对象中才能交换新的对象.
在GCC,Clang和其他人中,更改对象的类型可以像简单地更改虚拟表指针一样便宜,但在便携式C++中,除了通过构造新类型的对象之外,这是不可能的.
在我的原始用例中,对象也不能作为指针.
我想知道标准在重用内存方面的内容.
\n\n\n[basic.life]/8如果在一个对象的生命周期结束后,在该对象所占用的存储被重用或释放之前,在原对象所占用的存储位置创建了一个新对象,则指向该对象的指针原始对象、引用原始对象的引用或原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用来操作新对象,如果:
\n\n...
\n\n(8.4) \xe2\x80\x94 原始对象是类型的最派生对象 (1.8)
\nT,新对象是类型的最派生对象T(即,它们不是基类子对象)。
在您的示例中,对自身的调用kill()可能是有效的(如果发生这种情况sizeof(Animal)==sizeof(Dead),我认为不能保证),但大多数尝试使用Animal*指针或Animal&左值来进行调用会通过访问来触发未定义的行为生命周期已结束的对象。即使假设星星对齐并且 的子Animal对象Dead完美地覆盖原始独立Animal对象的原始位置,这样的指针或左值也不被认为是指前者,而是指现已过期的后者。