这是this question的后续行动。假设我有这段代码:
class Class {
public virtual method()
{
this->~Class();
new( this ) Class();
}
};
Class* object = new Class();
object->method();
delete object;
这是this answer建议的简化版本。
现在,在method()
内调用析构函数后,对象生存期结束,调用代码中的指针变量object
变为无效。然后在同一位置创建新对象。
这是否会使指向调用对象的指针再次生效?
答案 0 :(得分:4)
严格来说,这很好。然而,如果没有极端关心,它将成为UB的一个可怕的部分。例如,任何调用此方法的派生类都不会重新构造正确的类型 - 或者如果Class()
抛出异常会发生什么。此外,这并没有真正完成任何事情。
它不是严格意义上的UB,而是一大堆废话而且失败,应该在视线上燃烧。
答案 1 :(得分:4)
object
指针在任何时候都不会变为无效(假设您的析构函数不会调用delete this
)。你的对象从未被释放,它只调用了它的析构函数,即它已经清理了它的内部状态(关于实现,请注意标准严格定义了在析构函数调用后对象被销毁)。由于您已使用placement new来在完全相同的地址实例化新对象,因此技术上可以。
这个确切的场景包含在C ++标准的3.8.7节中:
如果在对象的生命周期结束之后和存储之前 对象占用的是重用或释放的,一个新的对象是 在原始对象占用的存储位置创建,a 指向原始对象的指针,引用的引用 到原始对象,或原始对象的名称 自动引用新对象,一旦生命周期 新对象已经开始,可以用来操纵新对象[...]
那就是说,这只是学习代码,作为生产代码,这很可怕:)
答案 2 :(得分:0)
指针只知道它的地址,只要你能确认新对象的地址是指针指向的地址,答案是肯定的。
在某些情况下,人们会相信地址不会改变,但在某些情况下,它会发生变化,例如使用C realloc()
时。但这是另一个故事。
答案 3 :(得分:0)
您可能需要重新考虑显式调用析构函数。如果您希望执行的代码恰好位于析构函数中,请将该代码移动到新方法并从析构函数中调用该方法以保留当前功能。析构函数实际上是用于超出范围的对象。
答案 4 :(得分:-2)
在被破坏的位置创建新对象不会使任何指针再次有效。它们可能指向有效的新对象,但不指向您最初引用的对象。
在销毁原始对象之前,您应该保证所有引用都被删除或以某种方式标记为无效。
调试这将是一个特别困难的情况。