在这个答案中,Ryan直接调用虚拟析构函数.我已经在VS2010中测试了代码,它正确地调用了所有析构函数(使用日志记录语句测试).这样做真的有效吗?这种方法有哪些问题,缺陷甚至是好处?
我只能将它视为真正强制重置实际类型的一种方法,即使它们不覆盖虚reset函数,因为它们至少必须在它们的析构函数中清理.
另外,对析构函数的调用会带来什么样的副作用呢?在这样的析构函数调用之后使用该对象是不确定的行为?如果一个人立即通过new (this) MyClass();电话重新初始化该怎么办?
我看到了关于Piotr Padlewski的cppcon的演示文稿,说明以下是未定义的行为:
int test(Base* a){
int sum = 0;
sum += a->foo();
sum += a->foo();
return sum;
}
int Base::foo(){
new (this) Derived;
return 1;
}
Run Code Online (Sandbox Code Playgroud)
注意:假设sizeof(Base) == sizeof(Derived)并且foo是虚拟的.
显然这很糟糕,但我很感兴趣为什么它是UB.我确实理解UB访问realloced指针,但他说,这是相同的.
相关问题:`new(this)MyClass();`直接调用析构函数后的未定义行为?在哪里说"ok,如果没有例外"
是否有效直接调用(虚拟)析构函数?它说的new (this) MyClass();结果是UB.(与上述问题相反)
程序可以通过重用对象占用的存储来结束任何对象的生命周期,或者通过使用非平凡的析构函数显式调用类类型的对象的析构函数来结束任何对象的生命周期.对于具有非平凡析构函数的类类型的对象,程序不需要在重用或释放对象占用的存储之前显式调用析构函数; 但是,如果没有显式调用析构函数或者如果没有使用delete-expression(5.3.5)来释放存储,则不应该隐式调用析构函数,并且任何程序都依赖于析构函数产生的副作用有未定义的行为.
这听起来好像没问题.
我在Placement new中找到了另一个新的贴图描述,并使用const成员分配了类
如果在对象的生命周期结束之后并且在重用或释放对象占用的存储之前,则在原始对象占用的存储位置创建新对象,指向原始对象的指针,引用引用原始对象,或者原始对象的名称将自动引用新对象,并且一旦新对象的生命周期开始,就可以用来操纵新对象,如果:
新对象的存储完全覆盖原始对象占用的存储位置,以及
新对象与原始对象的类型相同(忽略顶级cv限定符),和
原始对象的类型不是const限定的,如果是类类型,则不包含任何类型为const限定的非静态数据成员或引用类型,以及
原始对象是类型为T的派生程度最高的对象,新对象是类型为T的派生程度最高的对象(也就是说,它们不是基类子对象).
这似乎解释了UB.但这是真的吗?
这是不是意味着,我不能拥有std::vector<Base>?因为我假设由于它的预分配std::vector必须依赖placement-news和显式ctors.第4点要求它是最衍生的类型,Base显然不是.